Browse Source

Plan 9 from Bell Labs 2003-12-02

David du Colombier 20 years ago
parent
commit
d9ed3607cc
96 changed files with 7770 additions and 127 deletions
  1. 108 26
      dist/replica/plan9.db
  2. 110 0
      dist/replica/plan9.log
  3. 13 4
      rc/bin/yesterday
  4. 6 0
      sys/include/ape/cursor.h
  5. 521 0
      sys/include/ape/draw.h
  6. 1 0
      sys/include/ape/errno.h
  7. 6 0
      sys/include/ape/event.h
  8. 107 0
      sys/include/ape/fmt.h
  9. 6 0
      sys/include/ape/keyboard.h
  10. 6 0
      sys/include/ape/mouse.h
  11. 36 0
      sys/include/ape/qlock.h
  12. 60 0
      sys/include/ape/utf.h
  13. 2 2
      sys/lib/plumb/basic
  14. 3 0
      sys/man/1/tar
  15. 7 1
      sys/man/1/yesterday
  16. 16 8
      sys/src/9/ip/tcp.c
  17. 7 2
      sys/src/9/port/qio.c
  18. 4 0
      sys/src/ape/lib/ap/plan9/9errstr.c
  19. 14 0
      sys/src/ape/lib/ap/plan9/9mallocz.c
  20. 21 0
      sys/src/ape/lib/ap/plan9/9readn.c
  21. 3 0
      sys/src/ape/lib/ap/plan9/mkfile
  22. 365 0
      sys/src/ape/lib/ap/plan9/qlock.c
  23. 203 0
      sys/src/ape/lib/draw/colors.c
  24. 135 0
      sys/src/ape/lib/draw/libc.h
  25. 78 0
      sys/src/ape/lib/draw/mkfile
  26. 85 0
      sys/src/ape/lib/fmt/charstod.c
  27. 558 0
      sys/src/ape/lib/fmt/dofmt.c
  28. 61 0
      sys/src/ape/lib/fmt/dorfmt.c
  29. 28 0
      sys/src/ape/lib/fmt/errfmt.c
  30. 610 0
      sys/src/ape/lib/fmt/fltfmt.c
  31. 221 0
      sys/src/ape/lib/fmt/fmt.c
  32. 121 0
      sys/src/ape/lib/fmt/fmtdef.h
  33. 46 0
      sys/src/ape/lib/fmt/fmtfd.c
  34. 33 0
      sys/src/ape/lib/fmt/fmtfdflush.c
  35. 28 0
      sys/src/ape/lib/fmt/fmtlock.c
  36. 47 0
      sys/src/ape/lib/fmt/fmtprint.c
  37. 262 0
      sys/src/ape/lib/fmt/fmtquote.c
  38. 40 0
      sys/src/ape/lib/fmt/fmtrune.c
  39. 65 0
      sys/src/ape/lib/fmt/fmtstr.c
  40. 46 0
      sys/src/ape/lib/fmt/fmtvprint.c
  41. 28 0
      sys/src/ape/lib/fmt/fprint.c
  42. 59 0
      sys/src/ape/lib/fmt/mkfile
  43. 4 0
      sys/src/ape/lib/fmt/nan.h
  44. 76 0
      sys/src/ape/lib/fmt/nan64.c
  45. 57 0
      sys/src/ape/lib/fmt/pow10.c
  46. 28 0
      sys/src/ape/lib/fmt/print.c
  47. 65 0
      sys/src/ape/lib/fmt/runefmtstr.c
  48. 30 0
      sys/src/ape/lib/fmt/runeseprint.c
  49. 30 0
      sys/src/ape/lib/fmt/runesmprint.c
  50. 31 0
      sys/src/ape/lib/fmt/runesnprint.c
  51. 30 0
      sys/src/ape/lib/fmt/runesprint.c
  52. 39 0
      sys/src/ape/lib/fmt/runevseprint.c
  53. 37 0
      sys/src/ape/lib/fmt/runevsmprint.c
  54. 38 0
      sys/src/ape/lib/fmt/runevsnprint.c
  55. 27 0
      sys/src/ape/lib/fmt/seprint.c
  56. 27 0
      sys/src/ape/lib/fmt/smprint.c
  57. 28 0
      sys/src/ape/lib/fmt/snprint.c
  58. 27 0
      sys/src/ape/lib/fmt/sprint.c
  59. 539 0
      sys/src/ape/lib/fmt/strtod.c
  60. 4 0
      sys/src/ape/lib/fmt/strtod.h
  61. 39 0
      sys/src/ape/lib/fmt/test.c
  62. 31 0
      sys/src/ape/lib/fmt/vfprint.c
  63. 37 0
      sys/src/ape/lib/fmt/vseprint.c
  64. 36 0
      sys/src/ape/lib/fmt/vsmprint.c
  65. 37 0
      sys/src/ape/lib/fmt/vsnprint.c
  66. 16 0
      sys/src/ape/lib/fmt/werrstr.c
  67. 1 1
      sys/src/ape/lib/mkfile
  68. 17 0
      sys/src/ape/lib/utf/lib9.h
  69. 37 0
      sys/src/ape/lib/utf/mkfile
  70. 177 0
      sys/src/ape/lib/utf/rune.c
  71. 25 0
      sys/src/ape/lib/utf/runestrcat.c
  72. 35 0
      sys/src/ape/lib/utf/runestrchr.c
  73. 35 0
      sys/src/ape/lib/utf/runestrcmp.c
  74. 28 0
      sys/src/ape/lib/utf/runestrcpy.c
  75. 30 0
      sys/src/ape/lib/utf/runestrdup.c
  76. 32 0
      sys/src/ape/lib/utf/runestrecpy.c
  77. 24 0
      sys/src/ape/lib/utf/runestrlen.c
  78. 32 0
      sys/src/ape/lib/utf/runestrncat.c
  79. 37 0
      sys/src/ape/lib/utf/runestrncmp.c
  80. 33 0
      sys/src/ape/lib/utf/runestrncpy.c
  81. 30 0
      sys/src/ape/lib/utf/runestrrchr.c
  82. 44 0
      sys/src/ape/lib/utf/runestrstr.c
  83. 1152 0
      sys/src/ape/lib/utf/runetype.c
  84. 14 0
      sys/src/ape/lib/utf/utfdef.h
  85. 51 0
      sys/src/ape/lib/utf/utfecpy.c
  86. 38 0
      sys/src/ape/lib/utf/utflen.c
  87. 41 0
      sys/src/ape/lib/utf/utfnlen.c
  88. 46 0
      sys/src/ape/lib/utf/utfrrune.c
  89. 45 0
      sys/src/ape/lib/utf/utfrune.c
  90. 41 0
      sys/src/ape/lib/utf/utfutf.c
  91. 1 1
      sys/src/cmd/disk/mkext.c
  92. 2 2
      sys/src/cmd/hget.c
  93. 1 1
      sys/src/cmd/ip/httpd/webls.c
  94. 2 2
      sys/src/cmd/ratfs/misc.c
  95. 198 56
      sys/src/cmd/tar.c
  96. 32 21
      sys/src/cmd/upas/common/libsys.c

+ 108 - 26
dist/replica/plan9.db

@@ -90,7 +90,7 @@
 386/bin/aux/X509gen - 775 sys sys 1048341826 129186
 386/bin/aux/X509gen - 775 sys sys 1048341826 129186
 386/bin/aux/accupoint - 775 sys sys 1064598059 40841
 386/bin/aux/accupoint - 775 sys sys 1064598059 40841
 386/bin/aux/acidleak - 775 sys sys 1064598060 67816
 386/bin/aux/acidleak - 775 sys sys 1064598060 67816
-386/bin/aux/antiword - 775 sys sys 1069793954 511478
+386/bin/aux/antiword - 775 sys sys 1070288096 511478
 386/bin/aux/apm - 775 sys sys 1064598061 175778
 386/bin/aux/apm - 775 sys sys 1064598061 175778
 386/bin/aux/astarld - 775 sys sys 1064598061 63276
 386/bin/aux/astarld - 775 sys sys 1064598061 63276
 386/bin/aux/cddb - 775 sys sys 1064598062 70192
 386/bin/aux/cddb - 775 sys sys 1064598062 70192
@@ -230,9 +230,9 @@
 386/bin/fortune - 775 sys sys 1064598140 66084
 386/bin/fortune - 775 sys sys 1064598140 66084
 386/bin/fossil - 20000000775 sys sys 1042005470 0
 386/bin/fossil - 20000000775 sys sys 1042005470 0
 386/bin/fossil/conf - 775 sys sys 1056364255 1497
 386/bin/fossil/conf - 775 sys sys 1056364255 1497
-386/bin/fossil/flchk - 775 sys sys 1068717500 232696
-386/bin/fossil/flfmt - 775 sys sys 1068717501 230661
-386/bin/fossil/fossil - 775 sys sys 1068717502 345764
+386/bin/fossil/flchk - 775 sys sys 1070288097 232862
+386/bin/fossil/flfmt - 775 sys sys 1070288098 230827
+386/bin/fossil/fossil - 775 sys sys 1070288099 345606
 386/bin/freq - 775 sys sys 1064598145 60197
 386/bin/freq - 775 sys sys 1064598145 60197
 386/bin/fs - 20000000775 sys sys 954380769 0
 386/bin/fs - 20000000775 sys sys 954380769 0
 386/bin/fs/32vfs - 775 sys sys 1064598146 95907
 386/bin/fs/32vfs - 775 sys sys 1064598146 95907
@@ -252,7 +252,7 @@
 386/bin/gunzip - 775 sys sys 1064598211 79675
 386/bin/gunzip - 775 sys sys 1064598211 79675
 386/bin/gzip - 775 sys sys 1064598211 83770
 386/bin/gzip - 775 sys sys 1064598211 83770
 386/bin/hayes - 775 sys sys 1064598212 63307
 386/bin/hayes - 775 sys sys 1064598212 63307
-386/bin/hget - 775 sys sys 1068385800 222506
+386/bin/hget - 775 sys sys 1070286807 222506
 386/bin/history - 775 sys sys 1064598214 71890
 386/bin/history - 775 sys sys 1064598214 71890
 386/bin/hoc - 775 sys sys 1064598215 98708
 386/bin/hoc - 775 sys sys 1064598215 98708
 386/bin/html2ms - 775 sys sys 1064598215 64484
 386/bin/html2ms - 775 sys sys 1064598215 64484
@@ -284,8 +284,8 @@
 386/bin/ip/ppp - 775 sys sys 1069592368 217323
 386/bin/ip/ppp - 775 sys sys 1069592368 217323
 386/bin/ip/pppoe - 775 sys sys 1064598236 75233
 386/bin/ip/pppoe - 775 sys sys 1064598236 75233
 386/bin/ip/pptp - 775 sys sys 1064598237 123773
 386/bin/ip/pptp - 775 sys sys 1064598237 123773
-386/bin/ip/pptpd - 775 sys sys 1064598238 124288
-386/bin/ip/rarpd - 775 sys sys 1069592368 107845
+386/bin/ip/pptpd - 775 sys sys 1070288105 124153
+386/bin/ip/rarpd - 775 sys sys 1070288105 107748
 386/bin/ip/rexexec - 775 sys sys 1064598240 87398
 386/bin/ip/rexexec - 775 sys sys 1064598240 87398
 386/bin/ip/rip - 775 sys sys 1064598241 89573
 386/bin/ip/rip - 775 sys sys 1064598241 89573
 386/bin/ip/rlogind - 775 sys sys 1064598241 66139
 386/bin/ip/rlogind - 775 sys sys 1064598241 66139
@@ -316,10 +316,10 @@
 386/bin/ndb - 20000000775 sys sys 985743147 0
 386/bin/ndb - 20000000775 sys sys 985743147 0
 386/bin/ndb/cs - 775 sys sys 1069766560 144581
 386/bin/ndb/cs - 775 sys sys 1069766560 144581
 386/bin/ndb/csquery - 775 sys sys 1064598259 59890
 386/bin/ndb/csquery - 775 sys sys 1064598259 59890
-386/bin/ndb/dns - 775 sys sys 1069592370 218704
-386/bin/ndb/dnsdebug - 775 sys sys 1069592371 191053
+386/bin/ndb/dns - 775 sys sys 1070288106 218607
+386/bin/ndb/dnsdebug - 775 sys sys 1070288107 190956
 386/bin/ndb/dnsquery - 775 sys sys 1064598263 62194
 386/bin/ndb/dnsquery - 775 sys sys 1064598263 62194
-386/bin/ndb/dnstcp - 775 sys sys 1069592372 189767
+386/bin/ndb/dnstcp - 775 sys sys 1070288108 189670
 386/bin/ndb/ipquery - 775 sys sys 1069592372 91891
 386/bin/ndb/ipquery - 775 sys sys 1069592372 91891
 386/bin/ndb/mkdb - 775 sys sys 1064598265 62386
 386/bin/ndb/mkdb - 775 sys sys 1064598265 62386
 386/bin/ndb/mkhash - 775 sys sys 1069592372 82479
 386/bin/ndb/mkhash - 775 sys sys 1069592372 82479
@@ -527,7 +527,7 @@
 386/lib/libgeometry.a - 664 sys sys 1068385839 50806
 386/lib/libgeometry.a - 664 sys sys 1068385839 50806
 386/lib/libhtml.a - 664 sys sys 1068385840 220944
 386/lib/libhtml.a - 664 sys sys 1068385840 220944
 386/lib/libhttpd.a - 664 sys sys 1068385841 98914
 386/lib/libhttpd.a - 664 sys sys 1068385841 98914
-386/lib/libip.a - 664 sys sys 1069766546 34142
+386/lib/libip.a - 664 sys sys 1070288108 34142
 386/lib/libl.a - 664 sys sys 1068385841 5412
 386/lib/libl.a - 664 sys sys 1068385841 5412
 386/lib/libmach.a - 664 sys sys 1068558293 748290
 386/lib/libmach.a - 664 sys sys 1068558293 748290
 386/lib/libmemdraw.a - 664 sys sys 1068385844 292604
 386/lib/libmemdraw.a - 664 sys sys 1068385844 292604
@@ -3098,7 +3098,7 @@ rc/bin/whois - 775 sys sys 945617210 189
 rc/bin/window - 775 sys sys 1045504108 1742
 rc/bin/window - 775 sys sys 1045504108 1742
 rc/bin/wloc - 775 sys sys 969512017 191
 rc/bin/wloc - 775 sys sys 969512017 191
 rc/bin/wurl2txt - 755 sys sys 1017431148 296
 rc/bin/wurl2txt - 755 sys sys 1017431148 296
-rc/bin/yesterday - 775 sys sys 1044909161 2408
+rc/bin/yesterday - 775 sys sys 1070288432 2541
 rc/lib - 20000000775 sys sys 948037639 0
 rc/lib - 20000000775 sys sys 948037639 0
 rc/lib/rcmain - 664 sys sys 984696976 579
 rc/lib/rcmain - 664 sys sys 984696976 579
 sparc - 20000000775 sys sys 947991046 0
 sparc - 20000000775 sys sys 947991046 0
@@ -3319,12 +3319,17 @@ sys/include/ape/arpa/inet.h - 664 sys sys 944948760 4717
 sys/include/ape/assert.h - 664 sys sys 944948760 287
 sys/include/ape/assert.h - 664 sys sys 944948760 287
 sys/include/ape/bsd.h - 664 sys sys 944948760 1087
 sys/include/ape/bsd.h - 664 sys sys 944948760 1087
 sys/include/ape/ctype.h - 664 sys sys 1014927763 1654
 sys/include/ape/ctype.h - 664 sys sys 1014927763 1654
+sys/include/ape/cursor.h - 664 sys sys 1070327358 118
 sys/include/ape/dirent.h - 664 sys sys 1035117682 717
 sys/include/ape/dirent.h - 664 sys sys 1035117682 717
-sys/include/ape/errno.h - 664 sys sys 944948760 1505
+sys/include/ape/draw.h - 664 sys sys 1070327359 15998
+sys/include/ape/errno.h - 664 sys sys 1070327359 1525
 sys/include/ape/error.h - 664 sys sys 944948759 356
 sys/include/ape/error.h - 664 sys sys 944948759 356
+sys/include/ape/event.h - 664 sys sys 1070327358 117
 sys/include/ape/fcntl.h - 664 sys sys 969500385 1231
 sys/include/ape/fcntl.h - 664 sys sys 969500385 1231
+sys/include/ape/fmt.h - 664 sys sys 1070327361 3276
 sys/include/ape/grp.h - 664 sys sys 944948759 389
 sys/include/ape/grp.h - 664 sys sys 944948759 389
 sys/include/ape/inttypes.h - 664 sys sys 1038237535 452
 sys/include/ape/inttypes.h - 664 sys sys 1038237535 452
+sys/include/ape/keyboard.h - 664 sys sys 1070327358 120
 sys/include/ape/lib9.h - 664 sys sys 1014927764 1626
 sys/include/ape/lib9.h - 664 sys sys 1014927764 1626
 sys/include/ape/libl.h - 664 sys sys 944948760 331
 sys/include/ape/libl.h - 664 sys sys 944948760 331
 sys/include/ape/libnet.h - 664 sys sys 944948760 487
 sys/include/ape/libnet.h - 664 sys sys 944948760 487
@@ -3332,11 +3337,13 @@ sys/include/ape/libv.h - 664 sys sys 944948760 716
 sys/include/ape/limits.h - 664 sys sys 1014927764 2491
 sys/include/ape/limits.h - 664 sys sys 1014927764 2491
 sys/include/ape/locale.h - 664 sys sys 944948759 796
 sys/include/ape/locale.h - 664 sys sys 944948759 796
 sys/include/ape/lock.h - 664 sys sys 946054014 363
 sys/include/ape/lock.h - 664 sys sys 946054014 363
+sys/include/ape/mouse.h - 664 sys sys 1070327358 117
 sys/include/ape/netdb.h - 664 sys sys 1014927764 3907
 sys/include/ape/netdb.h - 664 sys sys 1014927764 3907
 sys/include/ape/netinet - 20000000775 sys sys 944948759 0
 sys/include/ape/netinet - 20000000775 sys sys 944948759 0
 sys/include/ape/netinet/in.h - 664 sys sys 944948759 4717
 sys/include/ape/netinet/in.h - 664 sys sys 944948759 4717
 sys/include/ape/netinet/tcp.h - 664 sys sys 944948759 0
 sys/include/ape/netinet/tcp.h - 664 sys sys 944948759 0
 sys/include/ape/pwd.h - 664 sys sys 944948759 423
 sys/include/ape/pwd.h - 664 sys sys 944948759 423
+sys/include/ape/qlock.h - 664 sys sys 1070327358 474
 sys/include/ape/regexp.h - 664 sys sys 988225292 1559
 sys/include/ape/regexp.h - 664 sys sys 988225292 1559
 sys/include/ape/select.h - 664 sys sys 944948760 779
 sys/include/ape/select.h - 664 sys sys 944948760 779
 sys/include/ape/setjmp.h - 664 sys sys 944948760 421
 sys/include/ape/setjmp.h - 664 sys sys 944948760 421
@@ -3365,6 +3372,7 @@ sys/include/ape/termios.h - 664 sys sys 944948760 2745
 sys/include/ape/time.h - 664 sys sys 944948760 1016
 sys/include/ape/time.h - 664 sys sys 944948760 1016
 sys/include/ape/u.h - 664 sys sys 1038237538 399
 sys/include/ape/u.h - 664 sys sys 1038237538 399
 sys/include/ape/unistd.h - 664 sys sys 944948760 3917
 sys/include/ape/unistd.h - 664 sys sys 944948760 3917
+sys/include/ape/utf.h - 664 sys sys 1070327359 1595
 sys/include/ape/utime.h - 664 sys sys 944948760 259
 sys/include/ape/utime.h - 664 sys sys 944948760 259
 sys/include/ar.h - 664 sys sys 1014929061 244
 sys/include/ar.h - 664 sys sys 1014929061 244
 sys/include/auth.h - 664 sys sys 1048614957 3469
 sys/include/auth.h - 664 sys sys 1048614957 3469
@@ -3939,7 +3947,7 @@ sys/lib/man/trademarks - 664 sys sys 958527089 1838
 sys/lib/mimetype - 664 sys sys 1064393944 5563
 sys/lib/mimetype - 664 sys sys 1064393944 5563
 sys/lib/newuser - 775 sys sys 1018386991 1229
 sys/lib/newuser - 775 sys sys 1018386991 1229
 sys/lib/plumb - 20000000775 sys sys 944957365 0
 sys/lib/plumb - 20000000775 sys sys 944957365 0
-sys/lib/plumb/basic - 664 sys sys 1069794119 2906
+sys/lib/plumb/basic - 664 sys sys 1070330856 2930
 sys/lib/plumb/fileaddr - 664 sys sys 944957365 88
 sys/lib/plumb/fileaddr - 664 sys sys 944957365 88
 sys/lib/postscript - 20000000775 sys sys 950322802 0
 sys/lib/postscript - 20000000775 sys sys 950322802 0
 sys/lib/postscript/afm - 20000000775 sys sys 950322802 0
 sys/lib/postscript/afm - 20000000775 sys sys 950322802 0
@@ -4690,7 +4698,7 @@ sys/man/1/sum - 664 sys sys 984772442 1390
 sys/man/1/syscall - 664 sys sys 1016466457 1439
 sys/man/1/syscall - 664 sys sys 1016466457 1439
 sys/man/1/tail - 664 sys sys 1017679307 1413
 sys/man/1/tail - 664 sys sys 1017679307 1413
 sys/man/1/tapefs - 664 sys sys 944959675 1731
 sys/man/1/tapefs - 664 sys sys 944959675 1731
-sys/man/1/tar - 664 sys sys 988225296 2317
+sys/man/1/tar - 664 sys sys 1070287474 2363
 sys/man/1/tbl - 664 sys sys 944959674 4308
 sys/man/1/tbl - 664 sys sys 944959674 4308
 sys/man/1/tcs - 664 sys sys 952627441 2575
 sys/man/1/tcs - 664 sys sys 952627441 2575
 sys/man/1/tee - 664 sys sys 969499886 351
 sys/man/1/tee - 664 sys sys 969499886 351
@@ -4713,7 +4721,7 @@ sys/man/1/wc - 664 sys sys 944959675 908
 sys/man/1/who - 664 sys sys 944959674 332
 sys/man/1/who - 664 sys sys 944959674 332
 sys/man/1/xd - 664 sys sys 944959674 1517
 sys/man/1/xd - 664 sys sys 944959674 1517
 sys/man/1/yacc - 664 sys sys 944959676 3273
 sys/man/1/yacc - 664 sys sys 944959676 3273
-sys/man/1/yesterday - 664 sys sys 1044909169 2202
+sys/man/1/yesterday - 664 sys sys 1070288431 2348
 sys/man/2 - 20000000775 sys sys 1017423721 0
 sys/man/2 - 20000000775 sys sys 1017423721 0
 sys/man/2/0intro - 664 sys sys 1044724217 11574
 sys/man/2/0intro - 664 sys sys 1044724217 11574
 sys/man/2/9p - 664 sys sys 1046886431 15221
 sys/man/2/9p - 664 sys sys 1046886431 15221
@@ -5215,7 +5223,7 @@ sys/src/9/ip/nullmedium.c - 664 sys sys 1022588099 491
 sys/src/9/ip/pktmedium.c - 664 sys sys 1045063516 1355
 sys/src/9/ip/pktmedium.c - 664 sys sys 1045063516 1355
 sys/src/9/ip/ptclbsum.c - 664 sys sys 1022588099 1243
 sys/src/9/ip/ptclbsum.c - 664 sys sys 1022588099 1243
 sys/src/9/ip/rudp.c - 664 sys sys 1055700790 21415
 sys/src/9/ip/rudp.c - 664 sys sys 1055700790 21415
-sys/src/9/ip/tcp.c - 664 sys sys 1067722615 65141
+sys/src/9/ip/tcp.c - 664 sys sys 1070287819 65399
 sys/src/9/ip/tripmedium.c - 664 sys sys 1045063515 7136
 sys/src/9/ip/tripmedium.c - 664 sys sys 1045063515 7136
 sys/src/9/ip/udp.c - 664 sys sys 1055700791 13069
 sys/src/9/ip/udp.c - 664 sys sys 1055700791 13069
 sys/src/9/mkfile - 664 sys sys 1063857477 205
 sys/src/9/mkfile - 664 sys sys 1063857477 205
@@ -5439,7 +5447,7 @@ sys/src/9/port/portfns.h - 664 sys sys 1068215525 11376
 sys/src/9/port/portmkfile - 664 sys sys 1067722766 2098
 sys/src/9/port/portmkfile - 664 sys sys 1067722766 2098
 sys/src/9/port/print.c - 664 sys sys 1014931178 227
 sys/src/9/port/print.c - 664 sys sys 1014931178 227
 sys/src/9/port/proc.c - 664 sys sys 1068393121 24882
 sys/src/9/port/proc.c - 664 sys sys 1068393121 24882
-sys/src/9/port/qio.c - 664 sys sys 1067953182 23406
+sys/src/9/port/qio.c - 664 sys sys 1070287837 23562
 sys/src/9/port/qlock.c - 664 sys sys 1067722765 3196
 sys/src/9/port/qlock.c - 664 sys sys 1067722765 3196
 sys/src/9/port/rdb.c - 664 sys sys 1018721202 1698
 sys/src/9/port/rdb.c - 664 sys sys 1018721202 1698
 sys/src/9/port/realtimesub.c - 664 sys sys 1055688540 9185
 sys/src/9/port/realtimesub.c - 664 sys sys 1055688540 9185
@@ -5984,7 +5992,10 @@ sys/src/ape/lib/ap/mips/vlop.s - 664 sys sys 1014921989 239
 sys/src/ape/lib/ap/mips/vlrt.c - 664 sys sys 1014921989 9001
 sys/src/ape/lib/ap/mips/vlrt.c - 664 sys sys 1014921989 9001
 sys/src/ape/lib/ap/mkfile - 664 sys sys 1014921988 244
 sys/src/ape/lib/ap/mkfile - 664 sys sys 1014921988 244
 sys/src/ape/lib/ap/plan9 - 20000000775 sys sys 1014921986 0
 sys/src/ape/lib/ap/plan9 - 20000000775 sys sys 1014921986 0
+sys/src/ape/lib/ap/plan9/9errstr.c - 664 sys sys 1070330880 31
+sys/src/ape/lib/ap/plan9/9mallocz.c - 664 sys sys 1070330880 148
 sys/src/ape/lib/ap/plan9/9read.c - 664 sys sys 1014921986 169
 sys/src/ape/lib/ap/plan9/9read.c - 664 sys sys 1014921986 169
+sys/src/ape/lib/ap/plan9/9readn.c - 664 sys sys 1070330880 221
 sys/src/ape/lib/ap/plan9/9wait.c - 664 sys sys 1014921986 1517
 sys/src/ape/lib/ap/plan9/9wait.c - 664 sys sys 1014921986 1517
 sys/src/ape/lib/ap/plan9/9write.c - 664 sys sys 1014921986 171
 sys/src/ape/lib/ap/plan9/9write.c - 664 sys sys 1014921986 171
 sys/src/ape/lib/ap/plan9/_buf.c - 664 sys sys 1048644332 9661
 sys/src/ape/lib/ap/plan9/_buf.c - 664 sys sys 1048644332 9661
@@ -6050,13 +6061,14 @@ sys/src/ape/lib/ap/plan9/link.c - 664 sys sys 1014921984 168
 sys/src/ape/lib/ap/plan9/lseek.c - 664 sys sys 1038237526 358
 sys/src/ape/lib/ap/plan9/lseek.c - 664 sys sys 1038237526 358
 sys/src/ape/lib/ap/plan9/malloc.c - 664 sys sys 1014921985 1957
 sys/src/ape/lib/ap/plan9/malloc.c - 664 sys sys 1014921985 1957
 sys/src/ape/lib/ap/plan9/mkdir.c - 664 sys sys 1014921984 353
 sys/src/ape/lib/ap/plan9/mkdir.c - 664 sys sys 1014921984 353
-sys/src/ape/lib/ap/plan9/mkfile - 664 sys sys 1030558746 1320
+sys/src/ape/lib/ap/plan9/mkfile - 664 sys sys 1070330880 1357
 sys/src/ape/lib/ap/plan9/nan.c - 664 sys sys 1014921985 614
 sys/src/ape/lib/ap/plan9/nan.c - 664 sys sys 1014921985 614
 sys/src/ape/lib/ap/plan9/open.c - 664 sys sys 1048644335 1088
 sys/src/ape/lib/ap/plan9/open.c - 664 sys sys 1048644335 1088
 sys/src/ape/lib/ap/plan9/opendir.c - 664 sys sys 1014921984 1881
 sys/src/ape/lib/ap/plan9/opendir.c - 664 sys sys 1014921984 1881
 sys/src/ape/lib/ap/plan9/pause.c - 664 sys sys 1014921985 124
 sys/src/ape/lib/ap/plan9/pause.c - 664 sys sys 1014921985 124
 sys/src/ape/lib/ap/plan9/pipe.c - 664 sys sys 1014921984 476
 sys/src/ape/lib/ap/plan9/pipe.c - 664 sys sys 1014921984 476
 sys/src/ape/lib/ap/plan9/profile.c - 664 sys sys 1014921985 2521
 sys/src/ape/lib/ap/plan9/profile.c - 664 sys sys 1014921985 2521
+sys/src/ape/lib/ap/plan9/qlock.c - 664 sys sys 1070330880 5124
 sys/src/ape/lib/ap/plan9/raise.c - 664 sys sys 1014921985 120
 sys/src/ape/lib/ap/plan9/raise.c - 664 sys sys 1014921985 120
 sys/src/ape/lib/ap/plan9/read.c - 664 sys sys 1014921984 767
 sys/src/ape/lib/ap/plan9/read.c - 664 sys sys 1014921984 767
 sys/src/ape/lib/ap/plan9/rename.c - 664 sys sys 1046643006 1282
 sys/src/ape/lib/ap/plan9/rename.c - 664 sys sys 1046643006 1282
@@ -6243,6 +6255,52 @@ sys/src/ape/lib/bsd/strcasecmp.c - 664 sys sys 1051635385 343
 sys/src/ape/lib/bsd/strdup.c - 664 sys sys 1014921995 182
 sys/src/ape/lib/bsd/strdup.c - 664 sys sys 1014921995 182
 sys/src/ape/lib/bsd/strncasecmp.c - 664 sys sys 1051635385 385
 sys/src/ape/lib/bsd/strncasecmp.c - 664 sys sys 1051635385 385
 sys/src/ape/lib/bsd/writev.c - 664 sys sys 1014921995 908
 sys/src/ape/lib/bsd/writev.c - 664 sys sys 1014921995 908
+sys/src/ape/lib/draw - 20000000775 sys sys 1070327097 0
+sys/src/ape/lib/draw/colors.c - 664 sys sys 1070327097 3607
+sys/src/ape/lib/draw/libc.h - 664 sys sys 1070327097 3476
+sys/src/ape/lib/draw/mkfile - 664 sys sys 1070327097 1176
+sys/src/ape/lib/fmt - 20000000775 sys sys 1070327381 0
+sys/src/ape/lib/fmt/charstod.c - 664 sys sys 1070327066 1995
+sys/src/ape/lib/fmt/dofmt.c - 664 sys sys 1070327066 10020
+sys/src/ape/lib/fmt/dorfmt.c - 664 sys sys 1070327066 1576
+sys/src/ape/lib/fmt/errfmt.c - 664 sys sys 1070327066 948
+sys/src/ape/lib/fmt/fltfmt.c - 664 sys sys 1070327066 10300
+sys/src/ape/lib/fmt/fmt.c - 664 sys sys 1070327067 4131
+sys/src/ape/lib/fmt/fmtdef.h - 664 sys sys 1070327067 3100
+sys/src/ape/lib/fmt/fmtfd.c - 664 sys sys 1070327067 1302
+sys/src/ape/lib/fmt/fmtfdflush.c - 664 sys sys 1070327067 1077
+sys/src/ape/lib/fmt/fmtlock.c - 664 sys sys 1070327067 868
+sys/src/ape/lib/fmt/fmtprint.c - 664 sys sys 1070327068 1257
+sys/src/ape/lib/fmt/fmtquote.c - 664 sys sys 1070327068 5582
+sys/src/ape/lib/fmt/fmtrune.c - 664 sys sys 1070327068 1120
+sys/src/ape/lib/fmt/fmtstr.c - 664 sys sys 1070327068 1509
+sys/src/ape/lib/fmt/fmtvprint.c - 664 sys sys 1070327068 1241
+sys/src/ape/lib/fmt/fprint.c - 664 sys sys 1070327069 946
+sys/src/ape/lib/fmt/mkfile - 664 sys sys 1070327069 794
+sys/src/ape/lib/fmt/nan.h - 664 sys sys 1070327069 114
+sys/src/ape/lib/fmt/nan64.c - 664 sys sys 1070327069 1176
+sys/src/ape/lib/fmt/pow10.c - 664 sys sys 1070327069 1987
+sys/src/ape/lib/fmt/print.c - 664 sys sys 1070327069 936
+sys/src/ape/lib/fmt/runefmtstr.c - 664 sys sys 1070327070 1544
+sys/src/ape/lib/fmt/runeseprint.c - 664 sys sys 1070327070 1016
+sys/src/ape/lib/fmt/runesmprint.c - 664 sys sys 1070327070 988
+sys/src/ape/lib/fmt/runesnprint.c - 664 sys sys 1070327070 1015
+sys/src/ape/lib/fmt/runesprint.c - 664 sys sys 1070327070 1004
+sys/src/ape/lib/fmt/runevseprint.c - 664 sys sys 1070327071 1132
+sys/src/ape/lib/fmt/runevsmprint.c - 664 sys sys 1070327071 1109
+sys/src/ape/lib/fmt/runevsnprint.c - 664 sys sys 1070327071 1142
+sys/src/ape/lib/fmt/seprint.c - 664 sys sys 1070327071 951
+sys/src/ape/lib/fmt/smprint.c - 664 sys sys 1070327071 923
+sys/src/ape/lib/fmt/snprint.c - 664 sys sys 1070327071 950
+sys/src/ape/lib/fmt/sprint.c - 664 sys sys 1070327072 991
+sys/src/ape/lib/fmt/strtod.c - 664 sys sys 1070327072 9359
+sys/src/ape/lib/fmt/strtod.h - 664 sys sys 1070327072 120
+sys/src/ape/lib/fmt/test.c - 664 sys sys 1070327072 1423
+sys/src/ape/lib/fmt/vfprint.c - 664 sys sys 1070327072 1026
+sys/src/ape/lib/fmt/vseprint.c - 664 sys sys 1070327072 1089
+sys/src/ape/lib/fmt/vsmprint.c - 664 sys sys 1070327073 1084
+sys/src/ape/lib/fmt/vsnprint.c - 664 sys sys 1070327073 1119
+sys/src/ape/lib/fmt/werrstr.c - 664 sys sys 1070330902 241
 sys/src/ape/lib/l - 20000000775 sys sys 1014921994 0
 sys/src/ape/lib/l - 20000000775 sys sys 1014921994 0
 sys/src/ape/lib/l/allprint.c - 664 sys sys 1014921994 458
 sys/src/ape/lib/l/allprint.c - 664 sys sys 1014921994 458
 sys/src/ape/lib/l/main.c - 664 sys sys 1014921994 128
 sys/src/ape/lib/l/main.c - 664 sys sys 1014921994 128
@@ -6250,7 +6308,7 @@ sys/src/ape/lib/l/mkfile - 664 sys sys 1014921994 180
 sys/src/ape/lib/l/reject.c - 664 sys sys 1014921994 985
 sys/src/ape/lib/l/reject.c - 664 sys sys 1014921994 985
 sys/src/ape/lib/l/yyless.c - 664 sys sys 1014921994 387
 sys/src/ape/lib/l/yyless.c - 664 sys sys 1014921994 387
 sys/src/ape/lib/l/yywrap.c - 664 sys sys 1014921994 70
 sys/src/ape/lib/l/yywrap.c - 664 sys sys 1014921994 70
-sys/src/ape/lib/mkfile - 664 sys sys 1014921994 190
+sys/src/ape/lib/mkfile - 664 sys sys 1070330862 203
 sys/src/ape/lib/net - 20000000775 sys sys 1014921993 0
 sys/src/ape/lib/net - 20000000775 sys sys 1014921993 0
 sys/src/ape/lib/net/announce.c - 664 sys sys 1014921993 3549
 sys/src/ape/lib/net/announce.c - 664 sys sys 1014921993 3549
 sys/src/ape/lib/net/dial.c - 664 sys sys 1014921993 2411
 sys/src/ape/lib/net/dial.c - 664 sys sys 1014921993 2411
@@ -6265,6 +6323,30 @@ sys/src/ape/lib/regexp/regexec.c - 664 sys sys 1014921993 4339
 sys/src/ape/lib/regexp/regsub.c - 664 sys sys 1014921993 1153
 sys/src/ape/lib/regexp/regsub.c - 664 sys sys 1014921993 1153
 sys/src/ape/lib/regexp/rregexec.c - 664 sys sys 1014921993 4189
 sys/src/ape/lib/regexp/rregexec.c - 664 sys sys 1014921993 4189
 sys/src/ape/lib/regexp/rregsub.c - 664 sys sys 1014921993 1188
 sys/src/ape/lib/regexp/rregsub.c - 664 sys sys 1014921993 1188
+sys/src/ape/lib/utf - 20000000775 sys sys 1070327378 0
+sys/src/ape/lib/utf/lib9.h - 664 sys sys 1070327090 330
+sys/src/ape/lib/utf/mkfile - 664 sys sys 1070327090 529
+sys/src/ape/lib/utf/rune.c - 664 sys sys 1070327090 3101
+sys/src/ape/lib/utf/runestrcat.c - 664 sys sys 1070327090 919
+sys/src/ape/lib/utf/runestrchr.c - 664 sys sys 1070327090 1002
+sys/src/ape/lib/utf/runestrcmp.c - 664 sys sys 1070327090 1016
+sys/src/ape/lib/utf/runestrcpy.c - 664 sys sys 1070327090 933
+sys/src/ape/lib/utf/runestrdup.c - 664 sys sys 1070327091 995
+sys/src/ape/lib/utf/runestrecpy.c - 664 sys sys 1070327091 997
+sys/src/ape/lib/utf/runestrlen.c - 664 sys sys 1070327091 889
+sys/src/ape/lib/utf/runestrncat.c - 664 sys sys 1070327091 1008
+sys/src/ape/lib/utf/runestrncmp.c - 664 sys sys 1070327091 1045
+sys/src/ape/lib/utf/runestrncpy.c - 664 sys sys 1070327093 1029
+sys/src/ape/lib/utf/runestrrchr.c - 664 sys sys 1070327093 977
+sys/src/ape/lib/utf/runestrstr.c - 664 sys sys 1070327093 1192
+sys/src/ape/lib/utf/runetype.c - 664 sys sys 1070327093 30457
+sys/src/ape/lib/utf/utfdef.h - 664 sys sys 1070327093 335
+sys/src/ape/lib/utf/utfecpy.c - 664 sys sys 1070327093 1268
+sys/src/ape/lib/utf/utflen.c - 664 sys sys 1070327094 1037
+sys/src/ape/lib/utf/utfnlen.c - 664 sys sys 1070327094 1112
+sys/src/ape/lib/utf/utfrrune.c - 664 sys sys 1070327094 1209
+sys/src/ape/lib/utf/utfrune.c - 664 sys sys 1070327094 1196
+sys/src/ape/lib/utf/utfutf.c - 664 sys sys 1070327094 1184
 sys/src/ape/lib/v - 20000000775 sys sys 1014921993 0
 sys/src/ape/lib/v - 20000000775 sys sys 1014921993 0
 sys/src/ape/lib/v/error.c - 664 sys sys 1014921993 197
 sys/src/ape/lib/v/error.c - 664 sys sys 1014921993 197
 sys/src/ape/lib/v/getfields.c - 664 sys sys 1014921993 3721
 sys/src/ape/lib/v/getfields.c - 664 sys sys 1014921993 3721
@@ -7300,7 +7382,7 @@ sys/src/cmd/disk/kfs/sub.c - 664 sys sys 1022008488 10804
 sys/src/cmd/disk/kfs/uid.c - 664 sys sys 1022008489 6719
 sys/src/cmd/disk/kfs/uid.c - 664 sys sys 1022008489 6719
 sys/src/cmd/disk/kfscmd.c - 664 sys sys 1015009135 1109
 sys/src/cmd/disk/kfscmd.c - 664 sys sys 1015009135 1109
 sys/src/cmd/disk/mbr.c - 664 sys sys 1063855285 4325
 sys/src/cmd/disk/mbr.c - 664 sys sys 1063855285 4325
-sys/src/cmd/disk/mkext.c - 664 sys sys 1069818199 5500
+sys/src/cmd/disk/mkext.c - 664 sys sys 1070287646 5506
 sys/src/cmd/disk/mkfile - 664 sys sys 1022385851 500
 sys/src/cmd/disk/mkfile - 664 sys sys 1022385851 500
 sys/src/cmd/disk/mkfs.c - 664 sys sys 1032059493 14298
 sys/src/cmd/disk/mkfs.c - 664 sys sys 1032059493 14298
 sys/src/cmd/disk/prep - 20000000775 sys sys 988249968 0
 sys/src/cmd/disk/prep - 20000000775 sys sys 988249968 0
@@ -9262,7 +9344,7 @@ sys/src/cmd/gzip/mkfile - 664 sys sys 984758036 125
 sys/src/cmd/gzip/unzip.c - 664 sys sys 1050689595 13603
 sys/src/cmd/gzip/unzip.c - 664 sys sys 1050689595 13603
 sys/src/cmd/gzip/zip.c - 664 sys sys 1033183074 7054
 sys/src/cmd/gzip/zip.c - 664 sys sys 1033183074 7054
 sys/src/cmd/gzip/zip.h - 664 sys sys 954778719 1428
 sys/src/cmd/gzip/zip.h - 664 sys sys 954778719 1428
-sys/src/cmd/hget.c - 664 sys sys 1067722871 22715
+sys/src/cmd/hget.c - 664 sys sys 1070286807 22715
 sys/src/cmd/history.c - 664 sys sys 1044909166 5810
 sys/src/cmd/history.c - 664 sys sys 1044909166 5810
 sys/src/cmd/hoc - 20000000775 sys sys 954036932 0
 sys/src/cmd/hoc - 20000000775 sys sys 954036932 0
 sys/src/cmd/hoc/code.c - 664 sys sys 944961000 10041
 sys/src/cmd/hoc/code.c - 664 sys sys 944961000 10041
@@ -9335,7 +9417,7 @@ sys/src/cmd/ip/httpd/netlib_history.c - 664 sys sys 1015096252 4744
 sys/src/cmd/ip/httpd/redirect.c - 664 sys sys 1042522766 2978
 sys/src/cmd/ip/httpd/redirect.c - 664 sys sys 1042522766 2978
 sys/src/cmd/ip/httpd/save.c - 664 sys sys 1015090172 3175
 sys/src/cmd/ip/httpd/save.c - 664 sys sys 1015090172 3175
 sys/src/cmd/ip/httpd/sendfd.c - 664 sys sys 1017679317 12134
 sys/src/cmd/ip/httpd/sendfd.c - 664 sys sys 1017679317 12134
-sys/src/cmd/ip/httpd/webls.c - 664 sys sys 1065646625 7233
+sys/src/cmd/ip/httpd/webls.c - 664 sys sys 1070288192 7269
 sys/src/cmd/ip/httpd/webls.denied - 664 sys sys 1064887847 3
 sys/src/cmd/ip/httpd/webls.denied - 664 sys sys 1064887847 3
 sys/src/cmd/ip/httpd/wikipost.c - 664 sys sys 1019678647 5917
 sys/src/cmd/ip/httpd/wikipost.c - 664 sys sys 1019678647 5917
 sys/src/cmd/ip/imap4d - 20000000775 sys sys 988249981 0
 sys/src/cmd/ip/imap4d - 20000000775 sys sys 988249981 0
@@ -10039,7 +10121,7 @@ sys/src/cmd/ramfs.c - 664 sys sys 1062759940 15377
 sys/src/cmd/ratfs - 20000000775 sys sys 1016943965 0
 sys/src/cmd/ratfs - 20000000775 sys sys 1016943965 0
 sys/src/cmd/ratfs/ctlfiles.c - 664 sys sys 1016943964 6694
 sys/src/cmd/ratfs/ctlfiles.c - 664 sys sys 1016943964 6694
 sys/src/cmd/ratfs/main.c - 664 sys sys 1016943964 6516
 sys/src/cmd/ratfs/main.c - 664 sys sys 1016943964 6516
-sys/src/cmd/ratfs/misc.c - 664 sys sys 1016943965 8560
+sys/src/cmd/ratfs/misc.c - 664 sys sys 1070288056 8563
 sys/src/cmd/ratfs/mkfile - 664 sys sys 1016943965 142
 sys/src/cmd/ratfs/mkfile - 664 sys sys 1016943965 142
 sys/src/cmd/ratfs/proto.c - 664 sys sys 1016943965 8528
 sys/src/cmd/ratfs/proto.c - 664 sys sys 1016943965 8528
 sys/src/cmd/ratfs/ratfs.h - 664 sys sys 1016943965 2743
 sys/src/cmd/ratfs/ratfs.h - 664 sys sys 1016943965 2743
@@ -10296,7 +10378,7 @@ sys/src/cmd/tapefs/tpfs.c - 664 sys sys 953243008 1966
 sys/src/cmd/tapefs/util.c - 664 sys sys 1014926385 2653
 sys/src/cmd/tapefs/util.c - 664 sys sys 1014926385 2653
 sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1014926385 3754
 sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1014926385 3754
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1014926385 3971
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1014926385 3971
-sys/src/cmd/tar.c - 664 sys sys 1029161018 12143
+sys/src/cmd/tar.c - 664 sys sys 1070287474 15531
 sys/src/cmd/tbl - 20000000775 sys sys 954038038 0
 sys/src/cmd/tbl - 20000000775 sys sys 954038038 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987
@@ -10667,7 +10749,7 @@ sys/src/cmd/upas/common/aux.c - 664 sys sys 1019498851 2300
 sys/src/cmd/upas/common/become.c - 664 sys sys 1015009623 430
 sys/src/cmd/upas/common/become.c - 664 sys sys 1015009623 430
 sys/src/cmd/upas/common/common.h - 664 sys sys 1015009623 1921
 sys/src/cmd/upas/common/common.h - 664 sys sys 1015009623 1921
 sys/src/cmd/upas/common/config.c - 664 sys sys 944961316 254
 sys/src/cmd/upas/common/config.c - 664 sys sys 944961316 254
-sys/src/cmd/upas/common/libsys.c - 664 sys sys 1055699577 14010
+sys/src/cmd/upas/common/libsys.c - 664 sys sys 1070287921 14107
 sys/src/cmd/upas/common/mail.c - 664 sys sys 944961315 1346
 sys/src/cmd/upas/common/mail.c - 664 sys sys 944961315 1346
 sys/src/cmd/upas/common/makefile - 664 sys sys 944961315 366
 sys/src/cmd/upas/common/makefile - 664 sys sys 944961315 366
 sys/src/cmd/upas/common/mkfile - 664 sys sys 1031707285 251
 sys/src/cmd/upas/common/mkfile - 664 sys sys 1031707285 251

+ 110 - 0
dist/replica/plan9.log

@@ -12817,3 +12817,113 @@
 1070033454 0 c 386/bin/fmt - 775 sys sys 1070032020 63683
 1070033454 0 c 386/bin/fmt - 775 sys sys 1070032020 63683
 1070033454 1 c sys/man/1/fmt - 664 sys sys 1070032221 1557
 1070033454 1 c sys/man/1/fmt - 664 sys sys 1070032221 1557
 1070033454 2 c sys/src/cmd/fmt.c - 664 sys sys 1070032009 4088
 1070033454 2 c sys/src/cmd/fmt.c - 664 sys sys 1070032009 4088
+1070287300 0 c 386/bin/hget - 775 sys sys 1070286807 222506
+1070287300 1 c sys/src/cmd/hget.c - 664 sys sys 1070286807 22715
+1070289103 0 c 386/bin/aux/antiword - 775 sys sys 1070288096 511478
+1070289103 1 c 386/bin/fossil/flchk - 775 sys sys 1070288097 232862
+1070289103 2 c 386/bin/fossil/flfmt - 775 sys sys 1070288098 230827
+1070289103 3 c 386/bin/fossil/fossil - 775 sys sys 1070288099 345606
+1070289103 4 c 386/bin/ip/pptpd - 775 sys sys 1070288105 124153
+1070289103 5 c 386/bin/ip/rarpd - 775 sys sys 1070288105 107748
+1070289103 6 c 386/bin/ndb/dns - 775 sys sys 1070288106 218607
+1070289103 7 c 386/bin/ndb/dnsdebug - 775 sys sys 1070288107 190956
+1070289103 8 c 386/bin/ndb/dnstcp - 775 sys sys 1070288108 189670
+1070289103 9 c 386/lib/libip.a - 664 sys sys 1070288108 34142
+1070289103 10 c rc/bin/yesterday - 775 sys sys 1070288432 2541
+1070289103 11 c sys/man/1/tar - 664 sys sys 1070287474 2363
+1070289103 12 c sys/man/1/yesterday - 664 sys sys 1070288431 2348
+1070289103 13 c sys/src/9/ip/tcp.c - 664 sys sys 1070287819 65399
+1070289103 14 c sys/src/9/port/qio.c - 664 sys sys 1070287837 23562
+1070289103 15 c sys/src/cmd/disk/mkext.c - 664 sys sys 1070287646 5506
+1070289103 16 c sys/src/cmd/ip/httpd/webls.c - 664 sys sys 1070288192 7269
+1070289103 17 c sys/src/cmd/ratfs/misc.c - 664 sys sys 1070288056 8563
+1070289103 18 c sys/src/cmd/upas/common/libsys.c - 664 sys sys 1070287921 14107
+1070289103 19 c sys/src/cmd/tar.c - 664 sys sys 1070287474 15531
+1070327406 0 a sys/include/ape/cursor.h - 664 sys sys 1070327358 118
+1070327406 1 a sys/include/ape/draw.h - 664 sys sys 1070327359 15998
+1070327406 2 c sys/include/ape/errno.h - 664 sys sys 1070327359 1525
+1070327406 3 a sys/include/ape/event.h - 664 sys sys 1070327358 117
+1070327406 4 a sys/include/ape/fmt.h - 664 sys sys 1070327361 3276
+1070327406 5 a sys/include/ape/keyboard.h - 664 sys sys 1070327358 120
+1070327406 6 a sys/include/ape/mouse.h - 664 sys sys 1070327358 117
+1070327406 7 a sys/include/ape/qlock.h - 664 sys sys 1070327358 474
+1070327406 8 a sys/include/ape/utf.h - 664 sys sys 1070327359 1595
+1070327406 9 a sys/src/ape/lib/draw - 20000000775 sys sys 1070327097 0
+1070327406 10 a sys/src/ape/lib/draw/colors.c - 664 sys sys 1070327097 3607
+1070327406 11 a sys/src/ape/lib/draw/libc.h - 664 sys sys 1070327097 3476
+1070327406 12 a sys/src/ape/lib/draw/mkfile - 664 sys sys 1070327097 1176
+1070327406 13 a sys/src/ape/lib/fmt - 20000000775 sys sys 1070327381 0
+1070327406 14 a sys/src/ape/lib/fmt/charstod.c - 664 sys sys 1070327066 1995
+1070327406 15 a sys/src/ape/lib/fmt/dofmt.c - 664 sys sys 1070327066 10020
+1070327406 16 a sys/src/ape/lib/fmt/dorfmt.c - 664 sys sys 1070327066 1576
+1070327406 17 a sys/src/ape/lib/fmt/errfmt.c - 664 sys sys 1070327066 948
+1070327406 18 a sys/src/ape/lib/fmt/fltfmt.c - 664 sys sys 1070327066 10300
+1070327406 19 a sys/src/ape/lib/fmt/fmt.c - 664 sys sys 1070327067 4131
+1070327406 20 a sys/src/ape/lib/fmt/fmtdef.h - 664 sys sys 1070327067 3100
+1070327406 21 a sys/src/ape/lib/fmt/fmtfd.c - 664 sys sys 1070327067 1302
+1070327406 22 a sys/src/ape/lib/fmt/fmtfdflush.c - 664 sys sys 1070327067 1077
+1070327406 23 a sys/src/ape/lib/fmt/fmtlock.c - 664 sys sys 1070327067 868
+1070327406 24 a sys/src/ape/lib/fmt/fmtprint.c - 664 sys sys 1070327068 1257
+1070327406 25 a sys/src/ape/lib/fmt/fmtquote.c - 664 sys sys 1070327068 5582
+1070327406 26 a sys/src/ape/lib/fmt/fmtrune.c - 664 sys sys 1070327068 1120
+1070327406 27 a sys/src/ape/lib/fmt/fmtstr.c - 664 sys sys 1070327068 1509
+1070327406 28 a sys/src/ape/lib/fmt/fmtvprint.c - 664 sys sys 1070327068 1241
+1070327406 29 a sys/src/ape/lib/fmt/fprint.c - 664 sys sys 1070327069 946
+1070327406 30 a sys/src/ape/lib/fmt/mkfile - 664 sys sys 1070327069 794
+1070327406 31 a sys/src/ape/lib/fmt/nan.h - 664 sys sys 1070327069 114
+1070327406 32 a sys/src/ape/lib/fmt/nan64.c - 664 sys sys 1070327069 1176
+1070327406 33 a sys/src/ape/lib/fmt/pow10.c - 664 sys sys 1070327069 1987
+1070327406 34 a sys/src/ape/lib/fmt/print.c - 664 sys sys 1070327069 936
+1070327406 35 a sys/src/ape/lib/fmt/runefmtstr.c - 664 sys sys 1070327070 1544
+1070327406 36 a sys/src/ape/lib/fmt/runeseprint.c - 664 sys sys 1070327070 1016
+1070327406 37 a sys/src/ape/lib/fmt/runesmprint.c - 664 sys sys 1070327070 988
+1070327406 38 a sys/src/ape/lib/fmt/runesnprint.c - 664 sys sys 1070327070 1015
+1070327406 39 a sys/src/ape/lib/fmt/runesprint.c - 664 sys sys 1070327070 1004
+1070327406 40 a sys/src/ape/lib/fmt/runevseprint.c - 664 sys sys 1070327071 1132
+1070327406 41 a sys/src/ape/lib/fmt/runevsmprint.c - 664 sys sys 1070327071 1109
+1070327406 42 a sys/src/ape/lib/fmt/runevsnprint.c - 664 sys sys 1070327071 1142
+1070327406 43 a sys/src/ape/lib/fmt/seprint.c - 664 sys sys 1070327071 951
+1070327406 44 a sys/src/ape/lib/fmt/smprint.c - 664 sys sys 1070327071 923
+1070327406 45 a sys/src/ape/lib/fmt/snprint.c - 664 sys sys 1070327071 950
+1070327406 46 a sys/src/ape/lib/fmt/sprint.c - 664 sys sys 1070327072 991
+1070327406 47 a sys/src/ape/lib/fmt/strtod.c - 664 sys sys 1070327072 9359
+1070327406 48 a sys/src/ape/lib/fmt/strtod.h - 664 sys sys 1070327072 120
+1070327406 49 a sys/src/ape/lib/fmt/test.c - 664 sys sys 1070327072 1423
+1070327406 50 a sys/src/ape/lib/fmt/vfprint.c - 664 sys sys 1070327072 1026
+1070327406 51 a sys/src/ape/lib/fmt/vseprint.c - 664 sys sys 1070327072 1089
+1070327406 52 a sys/src/ape/lib/fmt/vsmprint.c - 664 sys sys 1070327073 1084
+1070327406 53 a sys/src/ape/lib/fmt/vsnprint.c - 664 sys sys 1070327073 1119
+1070327406 54 a sys/src/ape/lib/fmt/werrstr.c - 664 sys sys 1070327073 235
+1070327406 55 a sys/src/ape/lib/utf - 20000000775 sys sys 1070327378 0
+1070327406 56 a sys/src/ape/lib/utf/lib9.h - 664 sys sys 1070327090 330
+1070327406 57 a sys/src/ape/lib/utf/mkfile - 664 sys sys 1070327090 529
+1070327406 58 a sys/src/ape/lib/utf/rune.c - 664 sys sys 1070327090 3101
+1070327406 59 a sys/src/ape/lib/utf/runestrcat.c - 664 sys sys 1070327090 919
+1070327406 60 a sys/src/ape/lib/utf/runestrchr.c - 664 sys sys 1070327090 1002
+1070327406 61 a sys/src/ape/lib/utf/runestrcmp.c - 664 sys sys 1070327090 1016
+1070327406 62 a sys/src/ape/lib/utf/runestrcpy.c - 664 sys sys 1070327090 933
+1070327406 63 a sys/src/ape/lib/utf/runestrdup.c - 664 sys sys 1070327091 995
+1070327406 64 a sys/src/ape/lib/utf/runestrecpy.c - 664 sys sys 1070327091 997
+1070327406 65 a sys/src/ape/lib/utf/runestrlen.c - 664 sys sys 1070327091 889
+1070327406 66 a sys/src/ape/lib/utf/runestrncat.c - 664 sys sys 1070327091 1008
+1070327406 67 a sys/src/ape/lib/utf/runestrncmp.c - 664 sys sys 1070327091 1045
+1070327406 68 a sys/src/ape/lib/utf/runestrncpy.c - 664 sys sys 1070327093 1029
+1070327406 69 a sys/src/ape/lib/utf/runestrrchr.c - 664 sys sys 1070327093 977
+1070327406 70 a sys/src/ape/lib/utf/runestrstr.c - 664 sys sys 1070327093 1192
+1070327406 71 a sys/src/ape/lib/utf/runetype.c - 664 sys sys 1070327093 30457
+1070327406 72 a sys/src/ape/lib/utf/utfdef.h - 664 sys sys 1070327093 335
+1070327406 73 a sys/src/ape/lib/utf/utfecpy.c - 664 sys sys 1070327093 1268
+1070327406 74 a sys/src/ape/lib/utf/utflen.c - 664 sys sys 1070327094 1037
+1070327406 75 a sys/src/ape/lib/utf/utfnlen.c - 664 sys sys 1070327094 1112
+1070327406 76 a sys/src/ape/lib/utf/utfrrune.c - 664 sys sys 1070327094 1209
+1070327406 77 a sys/src/ape/lib/utf/utfrune.c - 664 sys sys 1070327094 1196
+1070327406 78 a sys/src/ape/lib/utf/utfutf.c - 664 sys sys 1070327094 1184
+1070328706 0 c sys/lib/plumb/basic - 664 sys sys 1070327744 2922
+1070330908 0 c sys/lib/plumb/basic - 664 sys sys 1070330856 2930
+1070330908 1 a sys/src/ape/lib/ap/plan9/9errstr.c - 664 sys sys 1070330880 31
+1070330908 2 a sys/src/ape/lib/ap/plan9/9mallocz.c - 664 sys sys 1070330880 148
+1070330908 3 a sys/src/ape/lib/ap/plan9/9readn.c - 664 sys sys 1070330880 221
+1070330908 4 c sys/src/ape/lib/ap/plan9/mkfile - 664 sys sys 1070330880 1357
+1070330908 5 a sys/src/ape/lib/ap/plan9/qlock.c - 664 sys sys 1070330880 5124
+1070330908 6 c sys/src/ape/lib/fmt/werrstr.c - 664 sys sys 1070330902 241
+1070330908 7 c sys/src/ape/lib/mkfile - 664 sys sys 1070330862 203

+ 13 - 4
rc/bin/yesterday

@@ -56,6 +56,7 @@ fn Xbind {
 year=`{date|sed 's/.* //'}
 year=`{date|sed 's/.* //'}
 copy=Xecho
 copy=Xecho
 last=()
 last=()
+defdump=dump
 while(! ~ $#* 0 && ~ $1 -* && ! ~ $1 --){
 while(! ~ $#* 0 && ~ $1 -* && ! ~ $1 --){
 	switch($1){
 	switch($1){
 	case -a
 	case -a
@@ -76,6 +77,9 @@ while(! ~ $#* 0 && ~ $1 -* && ! ~ $1 --){
 	case -C
 	case -C
 		copy=Xcarefulcp
 		copy=Xcarefulcp
 		shift
 		shift
+	case -s
+		defdump=snap
+		shift
 # The slashnhack is always right.
 # The slashnhack is always right.
 #	case -N
 #	case -N
 #		slashnhack=no
 #		slashnhack=no
@@ -127,23 +131,28 @@ if(! ~ $status ''){
 
 
 for(i){
 for(i){
 	xpath=`{cleanname -d $dir -- $i}
 	xpath=`{cleanname -d $dir -- $i}
-	xdump=dump
+	xdump=$defdump
 	dumppath=$xpath
 	dumppath=$xpath
 	if(~ $slashnhack yes && ~ $xpath /n/*/*){
 	if(~ $slashnhack yes && ~ $xpath /n/*/*){
-		xdump=`{echo $xpath | sed 's:/n/([^/]+)/.*:\1dump:'}
+		xdump=`{echo $xpath | sed 's:/n/([^/]+)/.*:\1'$defdump':'}
 		dumppath=`{echo $xpath | sed 's:/n/[^/]+(/.*):\1:'}
 		dumppath=`{echo $xpath | sed 's:/n/[^/]+(/.*):\1:'}
 	}
 	}
 	if(! test -e /n/$xdump/$year)
 	if(! test -e /n/$xdump/$year)
 		9fs $xdump
 		9fs $xdump
 
 
-	if(~ $#last 0)
+	if(~ $#last 0){
 		xlast=`{ls -t /n/$xdump/$year|sed 1q}
 		xlast=`{ls -t /n/$xdump/$year|sed 1q}
+		switch($defdump){
+		case snap
+			xlast=`{ls -t $xlast|sed 1q}
+		}
+	}
 	if not
 	if not
 		xlast=/n/$xdump/$last
 		xlast=/n/$xdump/$last
 
 
 	if(! test -e $xlast){
 	if(! test -e $xlast){
 		echo 'yesterday:' \
 		echo 'yesterday:' \
-			`{echo $xlast|sed 's/.n.dump.(....).(..)(..)/\1 \2 \3/'} \
+			`{echo $xlast|sed 's/.n.'$defdump'.(....).(..)(..)/\1 \2 \3/'} \
 			'is not a backup day for' $xdump >[1=2]
 			'is not a backup day for' $xdump >[1=2]
 		exit 'bad date'
 		exit 'bad date'
 	}
 	}

+ 6 - 0
sys/include/ape/cursor.h

@@ -0,0 +1,6 @@
+#ifndef _RESEARCH_SOURCE
+  This header file is not defined in ANSI or POSIX
+#endif
+
+#include "/sys/include/cursor.h"
+

+ 521 - 0
sys/include/ape/draw.h

@@ -0,0 +1,521 @@
+#ifndef _RESEARCH_SOURCE
+  This header file is not defined in ANSI or POSIX
+#endif
+
+#pragma src "/sys/src/ape/lib/draw"
+#pragma lib "/$M/lib/ape/libdraw.a"
+
+typedef struct	Cachefont Cachefont;
+typedef struct	Cacheinfo Cacheinfo;
+typedef struct	Cachesubf Cachesubf;
+typedef struct	Display Display;
+typedef struct	Font Font;
+typedef struct	Fontchar Fontchar;
+typedef struct	Image Image;
+typedef struct	Mouse Mouse;
+typedef struct	Point Point;
+typedef struct	Rectangle Rectangle;
+typedef struct	RGB RGB;
+typedef struct	Screen Screen;
+typedef struct	Subfont Subfont;
+
+#pragma varargck	type	"R"	Rectangle
+#pragma varargck	type	"P"	Point
+extern	int	Rfmt(Fmt*);
+extern	int	Pfmt(Fmt*);
+
+enum
+{
+	DOpaque		= 0xFFFFFFFF,
+	DTransparent	= 0x00000000,		/* only useful for allocimage, memfillcolor */
+	DBlack		= 0x000000FF,
+	DWhite		= 0xFFFFFFFF,
+	DRed		= 0xFF0000FF,
+	DGreen		= 0x00FF00FF,
+	DBlue		= 0x0000FFFF,
+	DCyan		= 0x00FFFFFF,
+	DMagenta		= 0xFF00FFFF,
+	DYellow		= 0xFFFF00FF,
+	DPaleyellow	= 0xFFFFAAFF,
+	DDarkyellow	= 0xEEEE9EFF,
+	DDarkgreen	= 0x448844FF,
+	DPalegreen	= 0xAAFFAAFF,
+	DMedgreen	= 0x88CC88FF,
+	DDarkblue	= 0x000055FF,
+	DPalebluegreen= 0xAAFFFFFF,
+	DPaleblue		= 0x0000BBFF,
+	DBluegreen	= 0x008888FF,
+	DGreygreen	= 0x55AAAAFF,
+	DPalegreygreen	= 0x9EEEEEFF,
+	DYellowgreen	= 0x99994CFF,
+	DMedblue		= 0x000099FF,
+	DGreyblue	= 0x005DBBFF,
+	DPalegreyblue	= 0x4993DDFF,
+	DPurpleblue	= 0x8888CCFF,
+
+	DNotacolor	= 0xFFFFFF00,
+	DNofill		= DNotacolor,
+	
+};
+
+enum
+{
+	Displaybufsize	= 8000,
+	ICOSSCALE	= 1024,
+	Borderwidth =	4,
+};
+
+enum
+{
+	/* refresh methods */
+	Refbackup	= 0,
+	Refnone		= 1,
+	Refmesg		= 2
+};
+#define	NOREFRESH	((void*)-1)
+
+enum
+{
+	/* line ends */
+	Endsquare	= 0,
+	Enddisc		= 1,
+	Endarrow	= 2,
+	Endmask		= 0x1F
+};
+
+#define	ARROW(a, b, c)	(Endarrow|((a)<<5)|((b)<<14)|((c)<<23))
+
+typedef enum
+{
+	/* Porter-Duff compositing operators */
+	Clear	= 0,
+
+	SinD	= 8,
+	DinS	= 4,
+	SoutD	= 2,
+	DoutS	= 1,
+
+	S		= SinD|SoutD,
+	SoverD	= SinD|SoutD|DoutS,
+	SatopD	= SinD|DoutS,
+	SxorD	= SoutD|DoutS,
+
+	D		= DinS|DoutS,
+	DoverS	= DinS|DoutS|SoutD,
+	DatopS	= DinS|SoutD,
+	DxorS	= DoutS|SoutD,	/* == SxorD */
+
+	Ncomp = 12,
+} Drawop;
+
+/*
+ * image channel descriptors 
+ */
+enum {
+	CRed = 0,
+	CGreen,
+	CBlue,
+	CGrey,
+	CAlpha,
+	CMap,
+	CIgnore,
+	NChan,
+};
+
+#define __DC(type, nbits)	((((type)&15)<<4)|((nbits)&15))
+#define CHAN1(a,b)	__DC(a,b)
+#define CHAN2(a,b,c,d)	(CHAN1((a),(b))<<8|__DC((c),(d)))
+#define CHAN3(a,b,c,d,e,f)	(CHAN2((a),(b),(c),(d))<<8|__DC((e),(f)))
+#define CHAN4(a,b,c,d,e,f,g,h)	(CHAN3((a),(b),(c),(d),(e),(f))<<8|__DC((g),(h)))
+
+#define NBITS(c) ((c)&15)
+#define TYPE(c) (((c)>>4)&15)
+
+enum {
+	GREY1	= CHAN1(CGrey, 1),
+	GREY2	= CHAN1(CGrey, 2),
+	GREY4	= CHAN1(CGrey, 4),
+	GREY8	= CHAN1(CGrey, 8),
+	CMAP8	= CHAN1(CMap, 8),
+	RGB15	= CHAN4(CIgnore, 1, CRed, 5, CGreen, 5, CBlue, 5),
+	RGB16	= CHAN3(CRed, 5, CGreen, 6, CBlue, 5),
+	RGB24	= CHAN3(CRed, 8, CGreen, 8, CBlue, 8),
+	RGBA32	= CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8),
+	ARGB32	= CHAN4(CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8),	/* stupid VGAs */
+	XRGB32  = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8),
+};
+
+extern	char*	chantostr(char*, ulong);
+extern	ulong	strtochan(char*);
+extern	int		chantodepth(ulong);
+
+struct	Point
+{
+	int	x;
+	int	y;
+};
+
+struct Rectangle
+{
+	Point	min;
+	Point	max;
+};
+
+typedef void	(*Reffn)(Image*, Rectangle, void*);
+
+struct Screen
+{
+	Display	*display;	/* display holding data */
+	int	id;		/* id of system-held Screen */
+	Image	*image;		/* unused; for reference only */
+	Image	*fill;		/* color to paint behind windows */
+};
+
+struct Display
+{
+	QLock	qlock;
+	int		locking;	/*program is using lockdisplay */
+	int		dirno;
+	int		fd;
+	int		reffd;
+	int		ctlfd;
+	int		imageid;
+	int		local;
+	void		(*error)(Display*, char*);
+	char		*devdir;
+	char		*windir;
+	char		oldlabel[64];
+	ulong		dataqid;
+	Image		*white;
+	Image		*black;
+	Image		*opaque;
+	Image		*transparent;
+	Image		*image;
+	uchar		*buf;
+	int			bufsize;
+	uchar		*bufp;
+	Font		*defaultfont;
+	Subfont		*defaultsubfont;
+	Image		*windows;
+	Image		*screenimage;
+	int			_isnewdisplay;
+};
+
+struct Image
+{
+	Display		*display;	/* display holding data */
+	int		id;		/* id of system-held Image */
+	Rectangle	r;		/* rectangle in data area, local coords */
+	Rectangle 	clipr;		/* clipping region */
+	int		depth;		/* number of bits per pixel */
+	ulong	chan;
+	int		repl;		/* flag: data replicates to tile clipr */
+	Screen		*screen;	/* 0 if not a window */
+	Image		*next;	/* next in list of windows */
+};
+
+struct RGB
+{
+	ulong	red;
+	ulong	green;
+	ulong	blue;
+};
+
+/*
+ * Subfonts
+ *
+ * given char c, Subfont *f, Fontchar *i, and Point p, one says
+ *	i = f->info+c;
+ *	draw(b, Rect(p.x+i->left, p.y+i->top,
+ *		p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
+ *		color, f->bits, Pt(i->x, i->top));
+ *	p.x += i->width;
+ * to draw characters in the specified color (itself an Image) in Image b.
+ */
+
+struct	Fontchar
+{
+	int		x;		/* left edge of bits */
+	uchar		top;		/* first non-zero scan-line */
+	uchar		bottom;		/* last non-zero scan-line + 1 */
+	char		left;		/* offset of baseline */
+	uchar		width;		/* width of baseline */
+};
+
+struct	Subfont
+{
+	char		*name;
+	short		n;		/* number of chars in font */
+	uchar		height;		/* height of image */
+	char		ascent;		/* top of image to baseline */
+	Fontchar 	*info;		/* n+1 character descriptors */
+	Image		*bits;		/* of font */
+	int		ref;
+};
+
+enum
+{
+	/* starting values */
+	LOG2NFCACHE =	6,
+	NFCACHE =	(1<<LOG2NFCACHE),	/* #chars cached */
+	NFLOOK =	5,			/* #chars to scan in cache */
+	NFSUBF =	2,			/* #subfonts to cache */
+	/* max value */
+	MAXFCACHE =	1024+NFLOOK,		/* upper limit */
+	MAXSUBF =	50,			/* generous upper limit */
+	/* deltas */
+	DSUBF = 	4,
+	/* expiry ages */
+	SUBFAGE	=	10000,
+	CACHEAGE =	10000
+};
+
+struct Cachefont
+{
+	Rune		min;	/* lowest rune value to be taken from subfont */
+	Rune		max;	/* highest rune value+1 to be taken from subfont */
+	int		offset;	/* position in subfont of character at min */
+	char		*name;			/* stored in font */
+	char		*subfontname;		/* to access subfont */
+};
+
+struct Cacheinfo
+{
+	ushort		x;		/* left edge of bits */
+	uchar		width;		/* width of baseline */
+	schar		left;		/* offset of baseline */
+	Rune		value;	/* value of character at this slot in cache */
+	ushort		age;
+};
+
+struct Cachesubf
+{
+	ulong		age;	/* for replacement */
+	Cachefont	*cf;	/* font info that owns us */
+	Subfont		*f;	/* attached subfont */
+};
+
+struct Font
+{
+	char		*name;
+	Display		*display;
+	short		height;	/* max height of image, interline spacing */
+	short		ascent;	/* top of image to baseline */
+	short		width;	/* widest so far; used in caching only */	
+	short		nsub;	/* number of subfonts */
+	ulong		age;	/* increasing counter; used for LRU */
+	int		maxdepth;	/* maximum depth of all loaded subfonts */
+	int		ncache;	/* size of cache */
+	int		nsubf;	/* size of subfont list */
+	Cacheinfo	*cache;
+	Cachesubf	*subf;
+	Cachefont	**sub;	/* as read from file */
+	Image		*cacheimage;
+};
+
+#define	Dx(r)	((r).max.x-(r).min.x)
+#define	Dy(r)	((r).max.y-(r).min.y)
+
+/*
+ * Image management
+ */
+extern Image*	_allocimage(Image*, Display*, Rectangle, ulong, int, ulong, int, int);
+extern Image*	allocimage(Display*, Rectangle, ulong, int, ulong);
+extern uchar*	bufimage(Display*, int);
+extern int	bytesperline(Rectangle, int);
+extern void	closedisplay(Display*);
+extern void	drawerror(Display*, char*);
+extern int	flushimage(Display*, int);
+extern int	freeimage(Image*);
+extern int	_freeimage1(Image*);
+extern int	geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int);
+extern int	initdraw(void(*)(Display*, char*), char*, char*);
+extern int	newwindow(char*);
+extern Display*	initdisplay(char*, char*, void(*)(Display*, char*));
+extern int	loadimage(Image*, Rectangle, uchar*, int);
+extern int	cloadimage(Image*, Rectangle, uchar*, int);
+extern int	getwindow(Display*, int);
+extern int	gengetwindow(Display*, char*, Image**, Screen**, int);
+extern Image* readimage(Display*, int, int);
+extern Image* creadimage(Display*, int, int);
+extern int	unloadimage(Image*, Rectangle, uchar*, int);
+extern int	wordsperline(Rectangle, int);
+extern int	writeimage(int, Image*, int);
+extern Image*	namedimage(Display*, char*);
+extern int	nameimage(Image*, char*, int);
+extern Image* allocimagemix(Display*, ulong, ulong);
+
+/*
+ * Colors
+ */
+extern	void	readcolmap(Display*, RGB*);
+extern	void	writecolmap(Display*, RGB*);
+extern	ulong	setalpha(ulong, uchar);
+
+/*
+ * Windows
+ */
+extern Screen*	allocscreen(Image*, Image*, int);
+extern Image*	_allocwindow(Image*, Screen*, Rectangle, int, ulong);
+extern Image*	allocwindow(Screen*, Rectangle, int, ulong);
+extern void	bottomnwindows(Image**, int);
+extern void	bottomwindow(Image*);
+extern int	freescreen(Screen*);
+extern Screen*	publicscreen(Display*, int, ulong);
+extern void	topnwindows(Image**, int);
+extern void	topwindow(Image*);
+extern int	originwindow(Image*, Point, Point);
+
+/*
+ * Geometry
+ */
+extern Point		Pt(int, int);
+extern Rectangle	Rect(int, int, int, int);
+extern Rectangle	Rpt(Point, Point);
+extern Point		addpt(Point, Point);
+extern Point		subpt(Point, Point);
+extern Point		divpt(Point, int);
+extern Point		mulpt(Point, int);
+extern int		eqpt(Point, Point);
+extern int		eqrect(Rectangle, Rectangle);
+extern Rectangle	insetrect(Rectangle, int);
+extern Rectangle	rectaddpt(Rectangle, Point);
+extern Rectangle	rectsubpt(Rectangle, Point);
+extern Rectangle	canonrect(Rectangle);
+extern int		rectXrect(Rectangle, Rectangle);
+extern int		rectinrect(Rectangle, Rectangle);
+extern void		combinerect(Rectangle*, Rectangle);
+extern int		rectclip(Rectangle*, Rectangle);
+extern int		ptinrect(Point, Rectangle);
+extern void		replclipr(Image*, int, Rectangle);
+extern int		drawreplxy(int, int, int);	/* used to be drawsetxy */
+extern Point	drawrepl(Rectangle, Point);
+extern int		rgb2cmap(int, int, int);
+extern int		cmap2rgb(int);
+extern int		cmap2rgba(int);
+extern void		icossin(int, int*, int*);
+extern void		icossin2(int, int, int*, int*);
+
+/*
+ * Graphics
+ */
+extern void	draw(Image*, Rectangle, Image*, Image*, Point);
+extern void	drawop(Image*, Rectangle, Image*, Image*, Point, Drawop);
+extern void	gendraw(Image*, Rectangle, Image*, Point, Image*, Point);
+extern void	gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop);
+extern void	line(Image*, Point, Point, int, int, int, Image*, Point);
+extern void	lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop);
+extern void	poly(Image*, Point*, int, int, int, int, Image*, Point);
+extern void	polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
+extern void	fillpoly(Image*, Point*, int, int, Image*, Point);
+extern void	fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop);
+extern Point	string(Image*, Point, Image*, Point, Font*, char*);
+extern Point	stringop(Image*, Point, Image*, Point, Font*, char*, Drawop);
+extern Point	stringn(Image*, Point, Image*, Point, Font*, char*, int);
+extern Point	stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop);
+extern Point	runestring(Image*, Point, Image*, Point, Font*, Rune*);
+extern Point	runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop);
+extern Point	runestringn(Image*, Point, Image*, Point, Font*, Rune*, int);
+extern Point	runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop);
+extern Point	stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point);
+extern Point	stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop);
+extern Point	stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point);
+extern Point	stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop);
+extern Point	runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point);
+extern Point	runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop);
+extern Point	runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point);
+extern Point	runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop);
+extern Point	_string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop);
+extern Point	stringsubfont(Image*, Point, Image*, Subfont*, char*);
+extern int		bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point);
+extern int		bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop);
+extern int		bezspline(Image*, Point*, int, int, int, int, Image*, Point);
+extern int		bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
+extern int		bezsplinepts(Point*, int, Point**);
+extern int		fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point);
+extern int		fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop);
+extern int		fillbezspline(Image*, Point*, int, int, Image*, Point);
+extern int		fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop);
+extern void	ellipse(Image*, Point, int, int, int, Image*, Point);
+extern void	ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop);
+extern void	fillellipse(Image*, Point, int, int, Image*, Point);
+extern void	fillellipseop(Image*, Point, int, int, Image*, Point, Drawop);
+extern void	arc(Image*, Point, int, int, int, Image*, Point, int, int);
+extern void	arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop);
+extern void	fillarc(Image*, Point, int, int, Image*, Point, int, int);
+extern void	fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
+extern void	border(Image*, Rectangle, int, Image*, Point);
+extern void	borderop(Image*, Rectangle, int, Image*, Point, Drawop);
+
+/*
+ * Font management
+ */
+extern Font*	openfont(Display*, char*);
+extern Font*	buildfont(Display*, char*, char*);
+extern void	freefont(Font*);
+extern Font*	mkfont(Subfont*, Rune);
+extern int	cachechars(Font*, char**, Rune**, ushort*, int, int*, char**);
+extern void	agefont(Font*);
+extern Subfont*	allocsubfont(char*, int, int, int, Fontchar*, Image*);
+extern Subfont*	lookupsubfont(Display*, char*);
+extern void	installsubfont(char*, Subfont*);
+extern void	uninstallsubfont(Subfont*);
+extern void	freesubfont(Subfont*);
+extern Subfont*	readsubfont(Display*, char*, int, int);
+extern Subfont*	readsubfonti(Display*, char*, int, Image*, int);
+extern int	writesubfont(int, Subfont*);
+extern void	_unpackinfo(Fontchar*, uchar*, int);
+extern Point	stringsize(Font*, char*);
+extern int	stringwidth(Font*, char*);
+extern int	stringnwidth(Font*, char*, int);
+extern Point	runestringsize(Font*, Rune*);
+extern int	runestringwidth(Font*, Rune*);
+extern int	runestringnwidth(Font*, Rune*, int);
+extern Point	strsubfontwidth(Subfont*, char*);
+extern int	loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
+extern char*	subfontname(char*, char*, int);
+extern Subfont*	_getsubfont(Display*, char*);
+extern Subfont*	getdefont(Display*);
+extern void		lockdisplay(Display*);
+extern void	unlockdisplay(Display*);
+extern int		drawlsetrefresh(ulong, int, void*, void*);
+
+/*
+ * Predefined 
+ */
+extern	uchar	defontdata[];
+extern	int		sizeofdefont;
+extern	Point		ZP;
+extern	Rectangle	ZR;
+
+/*
+ * Set up by initdraw()
+ */
+extern	Display	*display;
+extern	Font		*font;
+extern	Image	*screen;
+extern	Screen	*_screen;
+extern	int	_cursorfd;
+extern	int	_drawdebug;	/* set to 1 to see errors from flushimage */
+extern	void	_setdrawop(Display*, Drawop);
+
+#define	BGSHORT(p)		(((p)[0]<<0) | ((p)[1]<<8))
+#define	BGLONG(p)		((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16))
+#define	BPSHORT(p, v)		((p)[0]=(v), (p)[1]=((v)>>8))
+#define	BPLONG(p, v)		(BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16))
+
+/*
+ * Compressed image file parameters and helper routines
+ */
+#define	NMATCH	3		/* shortest match possible */
+#define	NRUN	(NMATCH+31)	/* longest match possible */
+#define	NMEM	1024		/* window size */
+#define	NDUMP	128		/* maximum length of dump */
+#define	NCBLOCK	6000		/* size of compressed blocks */
+extern	void	_twiddlecompressed(uchar*, int);
+extern	int	_compblocksize(Rectangle, int);
+
+/* XXX backwards helps; should go */
+extern	int		log2[];
+extern	ulong	drawld2chan[];
+extern	void		drawsetdebug(int);

+ 1 - 0
sys/include/ape/errno.h

@@ -6,6 +6,7 @@ extern int errno;
 
 
 #define EDOM	1000
 #define EDOM	1000
 #define ERANGE	1001
 #define ERANGE	1001
+#define EPLAN9	1002
 
 
 #ifdef _POSIX_SOURCE
 #ifdef _POSIX_SOURCE
 
 

+ 6 - 0
sys/include/ape/event.h

@@ -0,0 +1,6 @@
+#ifndef _RESEARCH_SOURCE
+  This header file is not defined in ANSI or POSIX
+#endif
+
+#include "/sys/include/event.h"
+

+ 107 - 0
sys/include/ape/fmt.h

@@ -0,0 +1,107 @@
+#ifndef _FMT_H_
+#define _FMT_H_ 1
+#pragma lib "/$M/lib/ape/libfmt.a"
+#pragma src "/sys/src/ape/lib/fmt"
+
+#if defined(__cplusplus)
+extern "C" { 
+#endif
+
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <stdarg.h>
+#include <utf.h>
+
+typedef struct Fmt	Fmt;
+struct Fmt{
+	unsigned char	runes;		/* output buffer is runes or chars? */
+	void	*start;			/* of buffer */
+	void	*to;			/* current place in the buffer */
+	void	*stop;			/* end of the buffer; overwritten if flush fails */
+	int	(*flush)(Fmt *);	/* called when to == stop */
+	void	*farg;			/* to make flush a closure */
+	int	nfmt;			/* num chars formatted so far */
+	va_list	args;			/* args passed to dofmt */
+	int	r;			/* % format Rune */
+	int	width;
+	int	prec;
+	unsigned long	flags;
+};
+
+enum{
+	FmtWidth	= 1,
+	FmtLeft		= FmtWidth << 1,
+	FmtPrec		= FmtLeft << 1,
+	FmtSharp	= FmtPrec << 1,
+	FmtSpace	= FmtSharp << 1,
+	FmtSign		= FmtSpace << 1,
+	FmtZero		= FmtSign << 1,
+	FmtUnsigned	= FmtZero << 1,
+	FmtShort	= FmtUnsigned << 1,
+	FmtLong		= FmtShort << 1,
+	FmtVLong	= FmtLong << 1,
+	FmtComma	= FmtVLong << 1,
+	FmtByte		= FmtComma << 1,
+	FmtLDouble	= FmtByte << 1,
+
+	FmtFlag		= FmtLDouble << 1
+};
+
+extern	int	print(char*, ...);
+extern	char*	seprint(char*, char*, char*, ...);
+extern	char*	vseprint(char*, char*, char*, va_list);
+extern	int	snprint(char*, int, char*, ...);
+extern	int	vsnprint(char*, int, char*, va_list);
+extern	char*	smprint(char*, ...);
+extern	char*	vsmprint(char*, va_list);
+extern	int	sprint(char*, char*, ...);
+extern	int	fprint(int, char*, ...);
+extern	int	vfprint(int, char*, va_list);
+
+extern	int	runesprint(Rune*, char*, ...);
+extern	int	runesnprint(Rune*, int, char*, ...);
+extern	int	runevsnprint(Rune*, int, char*, va_list);
+extern	Rune*	runeseprint(Rune*, Rune*, char*, ...);
+extern	Rune*	runevseprint(Rune*, Rune*, char*, va_list);
+extern	Rune*	runesmprint(char*, ...);
+extern	Rune*	runevsmprint(char*, va_list);
+
+extern	int	fmtfdinit(Fmt*, int, char*, int);
+extern	int	fmtfdflush(Fmt*);
+extern	int	fmtstrinit(Fmt*);
+extern	char*	fmtstrflush(Fmt*);
+extern	int	runefmtstrinit(Fmt*);
+
+extern	int	quotestrfmt(Fmt *f);
+extern	void	quotefmtinstall(void);
+extern	int	(*fmtdoquote)(int);
+
+
+extern	int	fmtinstall(int, int (*)(Fmt*));
+extern	int	dofmt(Fmt*, char*);
+extern	int	fmtprint(Fmt*, char*, ...);
+extern	int	fmtvprint(Fmt*, char*, va_list);
+extern	int	fmtrune(Fmt*, int);
+extern	int	fmtstrcpy(Fmt*, char*);
+
+extern	double	fmtstrtod(const char *, char **);
+extern	double	fmtcharstod(int(*)(void*), void*);
+
+extern	int	werrstr(const char*, ...);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif

+ 6 - 0
sys/include/ape/keyboard.h

@@ -0,0 +1,6 @@
+#ifndef _RESEARCH_SOURCE
+  This header file is not defined in ANSI or POSIX
+#endif
+
+#include "/sys/include/keyboard.h"
+

+ 6 - 0
sys/include/ape/mouse.h

@@ -0,0 +1,6 @@
+#ifndef _RESEARCH_SOURCE
+  This header file is not defined in ANSI or POSIX
+#endif
+
+#include "/sys/include/mouse.h"
+

+ 36 - 0
sys/include/ape/qlock.h

@@ -0,0 +1,36 @@
+#ifndef __QLOCK_H_
+#define __QLOCK_H
+#ifndef _QLOCK_EXTENSION
+  This header file is an extension to ANSI/POSIX
+#endif
+#pragma lib "/$M/lib/ape/lib9.a"
+
+typedef struct QLp QLp;
+struct QLp
+{
+	int	inuse;
+	QLp	*next;
+	char	state;
+};
+
+typedef
+struct QLock
+{
+	Lock	lock;
+	int	locked;
+	QLp	*head;
+	QLp 	*tail;
+} QLock;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern	void	qlock(QLock*);
+extern	void	qunlock(QLock*);
+extern	int	canqlock(QLock*);
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 60 - 0
sys/include/ape/utf.h

@@ -0,0 +1,60 @@
+#ifndef _UTF_H_
+#define _UTF_H_ 1
+#pragma lib "/$M/lib/ape/libutf.a"
+#pragma src "/sys/src/ape/lib/utf"
+
+#if defined(__cplusplus)
+extern "C" { 
+#endif
+
+typedef unsigned short Rune;	/* 16 bits */
+
+enum
+{
+	UTFmax		= 3,		/* maximum bytes per rune */
+	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
+	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
+	Runeerror	= 0x80,		/* decoding error in UTF */
+};
+
+/*
+ * rune routines
+ */
+extern	int	runetochar(char*, Rune*);
+extern	int	chartorune(Rune*, char*);
+extern	int	runelen(long);
+extern	int	runenlen(Rune*, int);
+extern	int	fullrune(char*, int);
+extern	int	utflen(char*);
+extern	int	utfnlen(char*, long);
+extern	char*	utfrune(char*, long);
+extern	char*	utfrrune(char*, long);
+extern	char*	utfutf(char*, char*);
+extern	char*	utfecpy(char*, char*, char*);
+
+extern	Rune*	runestrcat(Rune*, Rune*);
+extern	Rune*	runestrchr(Rune*, Rune);
+extern	int	runestrcmp(Rune*, Rune*);
+extern	Rune*	runestrcpy(Rune*, Rune*);
+extern	Rune*	runestrncpy(Rune*, Rune*, long);
+extern	Rune*	runestrecpy(Rune*, Rune*, Rune*);
+extern	Rune*	runestrdup(Rune*);
+extern	Rune*	runestrncat(Rune*, Rune*, long);
+extern	int	runestrncmp(Rune*, Rune*, long);
+extern	Rune*	runestrrchr(Rune*, Rune);
+extern	long	runestrlen(Rune*);
+extern	Rune*	runestrstr(Rune*, Rune*);
+
+extern	Rune	tolowerrune(Rune);
+extern	Rune	totitlerune(Rune);
+extern	Rune	toupperrune(Rune);
+extern	int	isalpharune(Rune);
+extern	int	islowerrune(Rune);
+extern	int	isspacerune(Rune);
+extern	int	istitlerune(Rune);
+extern	int	isupperrune(Rune);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif

+ 2 - 2
sys/lib/plumb/basic

@@ -9,7 +9,7 @@ plumb to showmail
 
 
 # cheap http/gif,jpeg,ps,pdf renderer
 # cheap http/gif,jpeg,ps,pdf renderer
 type is text
 type is text
-data matches '(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=]+([:.][a-zA-Z0-9_?,%#~&/\-+=]+)*\.(jpe?g|JPE?G|gif|GIF|ps|PS|pdf|PDF)'
+data matches '(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=]+([:.][a-zA-Z0-9_?,%#~&/\-+=]+)*\.(jpe?g|JPE?G|gif|GIF|ps|PS|pdf|PDF|png|PNG)'
 plumb start rc -c 'hget '$0' | page -w'
 plumb start rc -c 'hget '$0' | page -w'
 
 
 # rtf files go to wdoc2txt
 # rtf files go to wdoc2txt
@@ -35,7 +35,7 @@ plumb start window rc -c '''echo % mail '''$0'; mail '$0
 # image files go to page
 # image files go to page
 type is text
 type is text
 data matches '[a-zA-Z¡-￿0-9_\-./]+'
 data matches '[a-zA-Z¡-￿0-9_\-./]+'
-data matches '([a-zA-Z¡-￿0-9_\-./]+)\.(jpe?g|JPE?G|gif|GIF|tiff?|TIFF?|ppm|bit)'
+data matches '([a-zA-Z¡-￿0-9_\-./]+)\.(jpe?g|JPE?G|gif|GIF|tiff?|TIFF?|ppm|PPM|bit|BIT|png|PNG)'
 arg isfile	$0
 arg isfile	$0
 plumb to image
 plumb to image
 plumb client page -wi
 plumb client page -wi

+ 3 - 0
sys/man/1/tar

@@ -77,6 +77,9 @@ a non-Plan 9 system.
 Use the next (numeric) argument as the group id for files in
 Use the next (numeric) argument as the group id for files in
 the output archive.
 the output archive.
 .TP
 .TP
+.BR p
+Create files in POSIX ustar format.
+.TP
 .B R
 .B R
 When extracting, ignore leading slash on file names,
 When extracting, ignore leading slash on file names,
 i.e., extract all files relative to the current directory.
 i.e., extract all files relative to the current directory.

+ 7 - 1
sys/man/1/yesterday

@@ -4,7 +4,7 @@ yesterday \- print file names from the dump
 .SH SYNOPSIS
 .SH SYNOPSIS
 .B yesterday
 .B yesterday
 [
 [
-.B -abcCdD
+.B -abcCdDs
 ] [
 ] [
 .B -n
 .B -n
 .I daysago
 .I daysago
@@ -90,6 +90,12 @@ option selects the dump
 .I daysago
 .I daysago
 prior to the current day.
 prior to the current day.
 .PP
 .PP
+The
+.B -s
+option selects the most recent snapshot instead of the most
+recent archived dump.  Snapshots may occur more frequently
+than dumps.
+.PP
 .I Yesterday
 .I Yesterday
 does not guarantee that the string it prints represents an existing file.
 does not guarantee that the string it prints represents an existing file.
 .SH EXAMPLES
 .SH EXAMPLES

+ 16 - 8
sys/src/9/ip/tcp.c

@@ -447,10 +447,11 @@ tcpstate(Conv *c, char *state, int n)
 	s = (Tcpctl*)(c->ptcl);
 	s = (Tcpctl*)(c->ptcl);
 
 
 	return snprint(state, n,
 	return snprint(state, n,
-		"%s srtt %d mdev %d cwin %lud swin %lud>>%d rwin %lud>>%d timer.start %d timer.count %d rerecv %d\n",
+		"%s srtt %d mdev %d cwin %lud swin %lud>>%d rwin %lud>>%d timer.start %d timer.count %d rerecv %d katimer.start %d katimer.count %d\n",
 		tcpstates[s->state], s->srtt, s->mdev,
 		tcpstates[s->state], s->srtt, s->mdev,
 		s->cwind, s->snd.wnd, s->rcv.scale, s->rcv.wnd, s->snd.scale,
 		s->cwind, s->snd.wnd, s->rcv.scale, s->rcv.wnd, s->snd.scale,
-		s->timer.start, s->timer.count, s->rerecv);
+		s->timer.start, s->timer.count, s->rerecv,
+		s->katimer.start, s->katimer.count);
 }
 }
 
 
 static int
 static int
@@ -2065,8 +2066,8 @@ reset:
 	/* fix up window */
 	/* fix up window */
 	seg.wnd <<= tcb->rcv.scale;
 	seg.wnd <<= tcb->rcv.scale;
 
 
-	if(tcb->kacounter > 0)
-		tcpsetkacounter(tcb);
+	/* every input packet in puts off the keep alive time out */
+	tcpsetkacounter(tcb);
 
 
 	switch(tcb->state) {
 	switch(tcb->state) {
 	case Closed:
 	case Closed:
@@ -2576,8 +2577,9 @@ tcpoutput(Conv *s)
 		}
 		}
 
 
 		tpriv->stats[OutSegs]++;
 		tpriv->stats[OutSegs]++;
-		if(tcb->kacounter > 0)
-			tcpgo(tpriv, &tcb->katimer);
+
+		/* put off the next keep alive */
+		tcpgo(tpriv, &tcb->katimer);
 
 
 		switch(version){
 		switch(version){
 		case V4:
 		case V4:
@@ -2659,8 +2661,7 @@ tcpsendka(Conv *s)
 }
 }
 
 
 /*
 /*
- *  if we've timed out, close the connection
- *  otherwise, send a keepalive and restart the timer
+ *  set connection to time out after 12 minutes
  */
  */
 void
 void
 tcpsetkacounter(Tcpctl *tcb)
 tcpsetkacounter(Tcpctl *tcb)
@@ -2669,6 +2670,11 @@ tcpsetkacounter(Tcpctl *tcb)
 	if(tcb->kacounter < 3)
 	if(tcb->kacounter < 3)
 		tcb->kacounter = 3;
 		tcb->kacounter = 3;
 }
 }
+
+/*
+ *  if we've timed out, close the connection
+ *  otherwise, send a keepalive and restart the timer
+ */
 void
 void
 tcpkeepalive(void *v)
 tcpkeepalive(void *v)
 {
 {
@@ -2704,6 +2710,8 @@ tcpstartka(Conv *s, char **f, int n)
 	int x;
 	int x;
 
 
 	tcb = (Tcpctl*)s->ptcl;
 	tcb = (Tcpctl*)s->ptcl;
+	if(tcb->state != Established)
+		return "connection must be in Establised state";
 	if(n > 1){
 	if(n > 1){
 		x = atoi(f[1]);
 		x = atoi(f[1]);
 		if(x >= MSPTICK)
 		if(x >= MSPTICK)

+ 7 - 2
sys/src/9/port/qio.c

@@ -1300,6 +1300,9 @@ qwrite(Queue *q, void *vp, int len)
 /*
 /*
  *  used by print() to write to a queue.  Since we may be splhi or not in
  *  used by print() to write to a queue.  Since we may be splhi or not in
  *  a process, don't qlock.
  *  a process, don't qlock.
+ *
+ *  this routine merges adjacent blocks if block n+1 will fit into
+ *  the free space of block n.
  */
  */
 int
 int
 qiwrite(Queue *q, void *vp, int len)
 qiwrite(Queue *q, void *vp, int len)
@@ -1324,8 +1327,10 @@ qiwrite(Queue *q, void *vp, int len)
 
 
 		ilock(q);
 		ilock(q);
 
 
-		/* don't queue over the limit, just lose the bytes */
-		if(q->len >= q->limit){
+		/* we use an artificially high limit for kernel prints since anything
+		 * over the limit gets dropped
+		 */
+		if(q->dlen >= 16*1024){
 			iunlock(q);
 			iunlock(q);
 			freeb(b);
 			freeb(b);
 			break;
 			break;

+ 4 - 0
sys/src/ape/lib/ap/plan9/9errstr.c

@@ -0,0 +1,4 @@
+#include "sys9.h"
+
+int
+_ERRSTR(

+ 14 - 0
sys/src/ape/lib/ap/plan9/9mallocz.c

@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <string.h>
+
+void*
+_MALLOCZ(int n, int clr)
+{
+	void *v;
+
+	v = malloc(n);
+	if(v && clr)
+		memset(v, 0, n);
+	return v;
+}
+

+ 21 - 0
sys/src/ape/lib/ap/plan9/9readn.c

@@ -0,0 +1,21 @@
+#include "sys9.h"
+
+long
+_READN(int f, void *av, long n)
+{
+	char *a;
+	long m, t;
+
+	a = av;
+	t = 0;
+	while(t < n){
+		m = _READ(f, a+t, n-t);
+		if(m <= 0){
+			if(t == 0)
+				return m;
+			break;
+		}
+		t += m;
+	}
+	return t;
+}

+ 3 - 0
sys/src/ape/lib/ap/plan9/mkfile

@@ -10,7 +10,9 @@ OFILES=\
 	_fdinfo.$O\
 	_fdinfo.$O\
 	_getpw.$O\
 	_getpw.$O\
 	_nap.$O\
 	_nap.$O\
+	9mallocz.$O\
 	9read.$O\
 	9read.$O\
+	9readn.$O\
 	9wait.$O\
 	9wait.$O\
 	9write.$O\
 	9write.$O\
 	access.$O\
 	access.$O\
@@ -67,6 +69,7 @@ OFILES=\
 	pause.$O\
 	pause.$O\
 	pipe.$O\
 	pipe.$O\
 	profile.$O\
 	profile.$O\
+	qlock.$O\
 	raise.$O\
 	raise.$O\
 	read.$O\
 	read.$O\
 	rename.$O\
 	rename.$O\

+ 365 - 0
sys/src/ape/lib/ap/plan9/qlock.c

@@ -0,0 +1,365 @@
+#define _LOCK_EXTENSION
+#define _QLOCK_EXTENSION
+#define _RESEARCH_SOURCE
+#include <u.h>
+#include <lock.h>
+#include <qlock.h>
+#include <stdlib.h>
+#include "sys9.h"
+
+#define rendezvous _RENDEZVOUS
+#define _rendezvousp rendezvous
+#define _tas tas
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+static struct {
+	QLp	*p;
+	QLp	x[1024];
+} ql = {
+	ql.x
+};
+
+enum
+{
+	Queuing,
+	QueuingR,
+	QueuingW,
+	Sleeping,
+};
+
+/* find a free shared memory location to queue ourselves in */
+static QLp*
+getqlp(void)
+{
+	QLp *p, *op;
+
+	op = ql.p;
+	for(p = op+1; ; p++){
+		if(p == &ql.x[nelem(ql.x)])
+			p = ql.x;
+		if(p == op)
+			abort();
+		if(_tas(&(p->inuse)) == 0){
+			ql.p = p;
+			p->next = nil;
+			break;
+		}
+	}
+	return p;
+}
+
+void
+qlock(QLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(!q->locked){
+		q->locked = 1;
+		unlock(&q->lock);
+		return;
+	}
+
+
+	/* chain into waiting list */
+	mp = getqlp();
+	p = q->tail;
+	if(p == nil)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->state = Queuing;
+	unlock(&q->lock);
+
+	/* wait */
+	while((*_rendezvousp)((ulong)mp, 1) == ~0)
+		;
+	mp->inuse = 0;
+}
+
+void
+qunlock(QLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	p = q->head;
+	if(p != nil){
+		/* wakeup head waiting process */
+		q->head = p->next;
+		if(q->head == nil)
+			q->tail = nil;
+		unlock(&q->lock);
+		while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
+			;
+		return;
+	}
+	q->locked = 0;
+	unlock(&q->lock);
+}
+
+int
+canqlock(QLock *q)
+{
+	if(!canlock(&q->lock))
+		return 0;
+	if(!q->locked){
+		q->locked = 1;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+#if 0
+
+void
+rlock(RWLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(q->writer == 0 && q->head == nil){
+		/* no writer, go for it */
+		q->readers++;
+		unlock(&q->lock);
+		return;
+	}
+
+	mp = getqlp();
+	p = q->tail;
+	if(p == 0)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->next = nil;
+	mp->state = QueuingR;
+	unlock(&q->lock);
+
+	/* wait in kernel */
+	while((*_rendezvousp)((ulong)mp, 1) == ~0)
+		;
+	mp->inuse = 0;
+}
+
+int
+canrlock(RWLock *q)
+{
+	lock(&q->lock);
+	if (q->writer == 0 && q->head == nil) {
+		/* no writer; go for it */
+		q->readers++;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+runlock(RWLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	if(q->readers <= 0)
+		abort();
+	p = q->head;
+	if(--(q->readers) > 0 || p == nil){
+		unlock(&q->lock);
+		return;
+	}
+
+	/* start waiting writer */
+	if(p->state != QueuingW)
+		abort();
+	q->head = p->next;
+	if(q->head == 0)
+		q->tail = 0;
+	q->writer = 1;
+	unlock(&q->lock);
+
+	/* wakeup waiter */
+	while((*_rendezvousp)((ulong)p, 0) == ~0)
+		;
+}
+
+void
+wlock(RWLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(q->readers == 0 && q->writer == 0){
+		/* noone waiting, go for it */
+		q->writer = 1;
+		unlock(&q->lock);
+		return;
+	}
+
+	/* wait */
+	p = q->tail;
+	mp = getqlp();
+	if(p == nil)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->next = nil;
+	mp->state = QueuingW;
+	unlock(&q->lock);
+
+	/* wait in kernel */
+	while((*_rendezvousp)((ulong)mp, 1) == ~0)
+		;
+	mp->inuse = 0;
+}
+
+int
+canwlock(RWLock *q)
+{
+	lock(&q->lock);
+	if (q->readers == 0 && q->writer == 0) {
+		/* no one waiting; go for it */
+		q->writer = 1;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+wunlock(RWLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	if(q->writer == 0)
+		abort();
+	p = q->head;
+	if(p == nil){
+		q->writer = 0;
+		unlock(&q->lock);
+		return;
+	}
+	if(p->state == QueuingW){
+		/* start waiting writer */
+		q->head = p->next;
+		if(q->head == nil)
+			q->tail = nil;
+		unlock(&q->lock);
+		while((*_rendezvousp)((ulong)p, 0) == ~0)
+			;
+		return;
+	}
+
+	if(p->state != QueuingR)
+		abort();
+
+	/* wake waiting readers */
+	while(q->head != nil && q->head->state == QueuingR){
+		p = q->head;
+		q->head = p->next;
+		q->readers++;
+		while((*_rendezvousp)((ulong)p, 0) == ~0)
+			;
+	}
+	if(q->head == nil)
+		q->tail = nil;
+	q->writer = 0;
+	unlock(&q->lock);
+}
+
+void
+rsleep(Rendez *r)
+{
+	QLp *t, *me;
+
+	if(!r->l)
+		abort();
+	lock(&r->l->lock);
+	/* we should hold the qlock */
+	if(!r->l->locked)
+		abort();
+
+	/* add ourselves to the wait list */
+	me = getqlp();
+	me->state = Sleeping;
+	if(r->head == nil)
+		r->head = me;
+	else
+		r->tail->next = me;
+	me->next = nil;
+	r->tail = me;
+
+	/* pass the qlock to the next guy */
+	t = r->l->head;
+	if(t){
+		r->l->head = t->next;
+		if(r->l->head == nil)
+			r->l->tail = nil;
+		unlock(&r->l->lock);
+		while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
+			;
+	}else{
+		r->l->locked = 0;
+		unlock(&r->l->lock);
+	}
+
+	/* wait for a wakeup */
+	while((*_rendezvousp)((ulong)me, 1) == ~0)
+		;
+	me->inuse = 0;
+}
+
+int
+rwakeup(Rendez *r)
+{
+	QLp *t;
+
+	/*
+	 * take off wait and put on front of queue
+	 * put on front so guys that have been waiting will not get starved
+	 */
+	
+	if(!r->l)
+		abort();
+	lock(&r->l->lock);
+	if(!r->l->locked)
+		abort();
+
+	t = r->head;
+	if(t == nil){
+		unlock(&r->l->lock);
+		return 0;
+	}
+
+	r->head = t->next;
+	if(r->head == nil)
+		r->tail = nil;
+
+	t->next = r->l->head;
+	r->l->head = t;
+	if(r->l->tail == nil)
+		r->l->tail = t;
+
+	t->state = Queuing;
+	unlock(&r->l->lock);
+	return 1;
+}
+
+int
+rwakeupall(Rendez *r)
+{
+	int i;
+
+	for(i=0; rwakeup(r); i++)
+		;
+	return i;
+}
+
+#endif

+ 203 - 0
sys/src/ape/lib/draw/colors.c

@@ -0,0 +1,203 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+
+char *argv0;
+
+static void
+_sysfatalimpl(char *fmt, va_list arg)
+{
+	char buf[1024];
+
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	if(argv0)
+		fprint(2, "%s: %s\n", argv0, buf);
+	else
+		fprint(2, "%s\n", buf);
+	exits(buf);
+}
+
+void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl;
+
+void
+sysfatal(char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	(*_sysfatal)(fmt, arg);
+	va_end(arg);
+}
+
+int nbit, npix;
+Image *pixel;
+Rectangle crect[256];
+
+Image *color[256];
+
+void
+eresized(int new)
+{
+	int x, y, i, n, nx, ny;
+	Rectangle r, b;
+
+	if(new && getwindow(display, Refnone) < 0){
+		fprint(2, "colors: can't reattach to window: %r\n");
+		exits("resized");
+	}
+	if(screen->depth > 8){
+		n = 256;
+		nx = 16;
+	}else{
+		n = 1<<screen->depth;
+		nx = 1<<(screen->depth/2);
+	}
+
+	ny = n/nx;
+	draw(screen, screen->r, display->white, nil, ZP);
+	r = insetrect(screen->r, 5);
+	r.min.y+=20;
+	b.max.y=r.min.y;
+	for(i=n-1, y=0; y!=ny; y++){
+		b.min.y=b.max.y;
+		b.max.y=r.min.y+(r.max.y-r.min.y)*(y+1)/ny;
+		b.max.x=r.min.x;
+		for(x=0; x!=nx; x++, --i){
+			b.min.x=b.max.x;
+			b.max.x=r.min.x+(r.max.x-r.min.x)*(x+1)/nx;
+			crect[i]=insetrect(b, 1);
+			draw(screen, crect[i], color[i], nil, ZP);
+		}
+	}
+	flushimage(display, 1);
+}
+
+char *buttons[] =
+{
+	"exit",
+	0
+};
+
+ulong
+grey(int i)
+{
+	if(i < 0)
+		return grey(0);
+	if(i > 255)
+		return grey(255);
+	return (i<<16)+(i<<8)+i;
+}
+
+Menu menu =
+{
+	buttons
+};
+
+int
+dither[16] =  {
+	0, 8, 2, 10,
+	12, 4, 14, 6,
+	3, 11, 1, 9,
+	15, 7, 13, 5
+};
+
+void
+main(int argc, char *argv[])
+{
+	Point p;
+	Mouse m;
+	int i, j, k, l, n, ramp, prev;
+	char buf[100];
+	char *fmt;
+	Image *dark;
+	ulong rgb;
+
+	ramp = 0;
+
+	fmt = "index %3d r %3lud g %3lud b %3lud 0x%.8luX        ";
+/*
+	ARGBEGIN{
+	default:
+		goto Usage;
+	case 'x':
+		fmt = "index %2luX r %3luX g %3luX b %3luX 0x%.8luX       ";
+		break;
+	case 'r':
+		ramp = 1;
+		break;
+	}ARGEND
+*/
+	argv0 = argv[0];
+	if(argc != 1){
+	Usage:
+		fprint(2, "Usage: %s [-rx]\n", argv0);
+		exits("usage");
+	}
+
+	if(initdraw(nil, nil, "colors") < 0)
+		sysfatal("initdraw failed: %r");
+	einit(Emouse);
+
+	for(i=0; i<256; i++){
+		if(ramp){
+			if(screen->chan == CMAP8){
+				/* dither the fine grey */
+				j = i-(i%17);
+				dark = allocimage(display, Rect(0,0,1,1), screen->chan, 1, (grey(j)<<8)+0xFF);
+				color[i] = allocimage(display, Rect(0,0,4,4), screen->chan, 1, (grey(j+17)<<8)+0xFF);
+				for(j=0; j<16; j++){
+					k = j%4;
+					l = j/4;
+					if(dither[j] > (i%17))
+						draw(color[i], Rect(k, l, k+1, l+1), dark, nil, ZP);
+				}
+				freeimage(dark);
+			}else
+				color[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, (grey(i)<<8)+0xFF);
+		}else
+			color[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, (cmap2rgb(i)<<8)+0xFF);
+		if(color[i] == nil)
+			sysfatal("can't allocate image: %r");
+	}
+	eresized(0);
+	prev = -1;
+	for(;;){
+		m = emouse();
+		switch(m.buttons){
+		case 1:
+			while(m.buttons){
+				if(screen->depth > 8)
+					n = 256;
+				else
+					n = 1<<screen->depth;
+				for(i=0; i!=n; i++)
+					if(i!=prev && ptinrect(m.xy, crect[i])){
+						if(ramp)
+							rgb = grey(i);
+						else
+							rgb = cmap2rgb(i);
+						sprint(buf, fmt,
+							i,
+							(rgb>>16)&0xFF,
+							(rgb>>8)&0xFF,
+							rgb&0xFF,
+							(rgb<<8) | 0xFF);
+						p = addpt(screen->r.min, Pt(2,2));
+						draw(screen, Rpt(p, addpt(p, stringsize(font, buf))), display->white, nil, p);
+						string(screen, p, display->black, ZP, font, buf);
+						prev=i;
+						break;
+					}
+				m = emouse();
+			}
+			break;
+
+		case 4:
+			switch(emenuhit(3, &m, &menu)){
+			case 0:
+				exits(0);
+			}
+		}
+	}
+}

+ 135 - 0
sys/src/ape/lib/draw/libc.h

@@ -0,0 +1,135 @@
+#define _LOCK_EXTENSION
+#define _QLOCK_EXTENSION
+#define _BSD_EXTENSION
+#include <sys/types.h>
+#include <lock.h>
+#include <qlock.h>
+#include <lib9.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bsd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <utf.h>
+#include <fmt.h>
+#include <signal.h>
+
+typedef
+struct Qid
+{
+	uvlong	path;
+	ulong	vers;
+	uchar	type;
+} Qid;
+
+typedef
+struct Dir {
+	/* system-modified data */
+	ushort	type;	/* server type */
+	uint	dev;	/* server subtype */
+	/* file data */
+	Qid	qid;	/* unique id from server */
+	ulong	mode;	/* permissions */
+	ulong	atime;	/* last read time */
+	ulong	mtime;	/* last write time */
+	vlong	length;	/* file length: see <u.h> */
+	char	*name;	/* last element of path */
+	char	*uid;	/* owner name */
+	char	*gid;	/* group name */
+	char	*muid;	/* last modifier name */
+} Dir;
+
+uint	_convM2D(uchar*, uint, Dir*, char*);
+uint	_convD2M(Dir*, uchar*, uint);
+Dir	*_dirstat(char*);
+int	_dirwstat(char*, Dir*);
+Dir	*_dirfstat(int);
+int	_dirfwstat(int, Dir*);
+long	_dirread(int, Dir**);
+long _dirreadall(int, Dir**);
+void _nulldir(Dir*);
+uint _sizeD2M(Dir*);
+
+typedef
+struct Waitmsg
+{
+	int pid;	/* of loved one */
+	unsigned long time[3];	/* of loved one & descendants */
+	char	*msg;
+} Waitmsg;
+
+
+extern	int	_AWAIT(char*, int);
+extern	int	_ALARM(unsigned long);
+extern	int	_BIND(const char*, const char*, int);
+extern	int	_CHDIR(const char*);
+extern	int	_CLOSE(int);
+extern	int	_CREATE(char*, int, unsigned long);
+extern	int	_DUP(int, int);
+extern	int	_ERRSTR(char*, unsigned int);
+extern	int	_EXEC(char*, char*[]);
+extern	void	_EXITS(char *);
+extern	int	_FD2PATH(int, char*, int);
+extern	int	_FAUTH(int, char*);
+extern	int	_FSESSION(int, char*, int);
+extern	int	_FSTAT(int, unsigned char*, int);
+extern	int	_FWSTAT(int, unsigned char*, int);
+extern	int	_MOUNT(int, int, const char*, int, const char*);
+extern	int	_NOTED(int);
+extern	int	_NOTIFY(int(*)(void*, char*));
+extern	int	_OPEN(const char*, int);
+extern	int	_PIPE(int*);
+extern	long	_PREAD(int, void*, long, long long);
+extern	long	_PWRITE(int, void*, long, long long);
+extern	long	_READ(int, void*, long);
+extern	int	_REMOVE(const char*);
+extern	int	_RENDEZVOUS(unsigned long, unsigned long);
+extern	int	_RFORK(int);
+extern	int	_SEGATTACH(int, char*, void*, unsigned long);
+extern	int	_SEGBRK(void*, void*);
+extern	int	_SEGDETACH(void*);
+extern	int	_SEGFLUSH(void*, unsigned long);
+extern	int	_SEGFREE(void*, unsigned long);
+extern	long long	_SEEK(int, long long, int);
+extern	int	_SLEEP(long);
+extern	int	_STAT(const char*, unsigned char*, int);
+extern	Waitmsg*	_WAIT(void);
+extern	long	_WRITE(int, const void*, long);
+extern	int	_WSTAT(const char*, unsigned char*, int);
+extern 	void *_MALLOCZ(int, int);
+extern	int	_WERRSTR(char*, ...);
+extern	long	_READN(int, void*, long);
+
+#define dirstat _dirstat
+#define dirfstat _dirfstat
+
+#define OREAD 0
+#define OWRITE 1
+#define ORDWR 2
+#define OCEXEC 32
+
+#define AREAD 4
+#define AWRITE 2
+#define AEXEC 1
+#define AEXIST 0
+
+#define open _OPEN
+#define close _CLOSE
+#define read _READ
+#define write _WRITE
+#define _exits(s) _exit(s && *(char*)s ? 1 : 0)
+#define exits(s) exit(s && *(char*)s ? 1 : 0)
+#define create _CREATE
+#define pread _PREAD
+#define readn _READN
+#define mallocz _MALLOCZ
+
+/* assume being called as in event.c */
+#define postnote(x, pid, msg) kill(pid, SIGTERM)
+#define atnotify(x, y) signal(SIGTERM, ekill)
+
+/* assume being called as in init.c */
+#define iounit(x) (32*1024)
+
+#define ERRMAX 128

+ 78 - 0
sys/src/ape/lib/draw/mkfile

@@ -0,0 +1,78 @@
+APE=/sys/src/ape
+<$APE/config
+
+LIB=/$objtype/lib/ape/libdraw.a
+
+OFILES=\
+	alloc.$O\
+	allocimagemix.$O\
+	arith.$O\
+	bezier.$O\
+	border.$O\
+	buildfont.$O\
+	bytesperline.$O\
+	chan.$O\
+	cloadimage.$O\
+	computil.$O\
+	creadimage.$O\
+	debug.$O\
+	defont.$O\
+	draw.$O\
+	drawrepl.$O\
+	egetrect.$O\
+	ellipse.$O\
+	emenuhit.$O\
+	event.$O\
+	fmt.$O\
+	font.$O\
+	freesubfont.$O\
+	getdefont.$O\
+	getsubfont.$O\
+	icossin.$O\
+	icossin2.$O\
+	init.$O\
+	line.$O\
+	mkfont.$O\
+	newwindow.$O\
+	openfont.$O\
+	poly.$O\
+	loadimage.$O\
+	readimage.$O\
+	readsubfont.$O\
+	rectclip.$O\
+	replclipr.$O\
+	rgb.$O\
+	string.$O\
+	stringbg.$O\
+	stringsubfont.$O\
+	stringwidth.$O\
+	subfont.$O\
+	subfontcache.$O\
+	subfontname.$O\
+	unloadimage.$O\
+	window.$O\
+	writecolmap.$O\
+	writeimage.$O\
+	writesubfont.$O\
+
+HFILES=\
+	/sys/include/ape/draw.h\
+	/sys/include/ape/event.h\
+	/sys/include/ape/mouse.h\
+	/sys/include/ape/keyboard.h\
+
+UPDATE=\
+	mkfile\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+	${LIB:/$objtype/%=/386/%}\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c $CFLAGS -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_RESEARCH_SOURCE -I.
+
+%.$O: /sys/src/libdraw/%.c
+	$CC $CFLAGS /sys/src/libdraw/$stem.c
+
+$O.colors: colors.$O
+	$LD -o $target colors.$O

+ 85 - 0
sys/src/ape/lib/fmt/charstod.c

@@ -0,0 +1,85 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp).  The last call it makes to f terminates the
+ * scan, so is not a character in the number.  It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+double
+fmtcharstod(int(*f)(void*), void *vp)
+{
+	double num, dem;
+	int neg, eneg, dig, exp, c;
+
+	num = 0;
+	neg = 0;
+	dig = 0;
+	exp = 0;
+	eneg = 0;
+
+	c = (*f)(vp);
+	while(c == ' ' || c == '\t')
+		c = (*f)(vp);
+	if(c == '-' || c == '+'){
+		if(c == '-')
+			neg = 1;
+		c = (*f)(vp);
+	}
+	while(c >= '0' && c <= '9'){
+		num = num*10 + c-'0';
+		c = (*f)(vp);
+	}
+	if(c == '.')
+		c = (*f)(vp);
+	while(c >= '0' && c <= '9'){
+		num = num*10 + c-'0';
+		dig++;
+		c = (*f)(vp);
+	}
+	if(c == 'e' || c == 'E'){
+		c = (*f)(vp);
+		if(c == '-' || c == '+'){
+			if(c == '-'){
+				dig = -dig;
+				eneg = 1;
+			}
+			c = (*f)(vp);
+		}
+		while(c >= '0' && c <= '9'){
+			exp = exp*10 + c-'0';
+			c = (*f)(vp);
+		}
+	}
+	exp -= dig;
+	if(exp < 0){
+		exp = -exp;
+		eneg = !eneg;
+	}
+	dem = __fmtpow10(exp);
+	if(eneg)
+		num /= dem;
+	else
+		num *= dem;
+	if(neg)
+		return -num;
+	return num;
+}

+ 558 - 0
sys/src/ape/lib/fmt/dofmt.c

@@ -0,0 +1,558 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+int
+dofmt(Fmt *f, char *fmt)
+{
+	Rune rune, *rt, *rs;
+	int r;
+	char *t, *s;
+	int n, nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = (Rune*)f->to;
+			rs = (Rune*)f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself)
+					fmt++;
+				else{
+					fmt += chartorune(&rune, fmt);
+					r = rune;
+				}
+				FMTRCHAR(f, rt, rs, r);
+			}
+			fmt++;
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = (char*)f->to;
+			s = (char*)f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself){
+					FMTCHAR(f, t, s, r);
+					fmt++;
+				}else{
+					n = chartorune(&rune, fmt);
+					if(t + n > s){
+						t = (char*)__fmtflush(f, t, n);
+						if(t != nil)
+							s = (char*)f->stop;
+						else
+							return -1;
+					}
+					while(n--)
+						*t++ = *fmt++;
+				}
+			}
+			fmt++;
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = (char*)__fmtdispatch(f, fmt, 0);
+		if(fmt == nil)
+			return -1;
+	}
+	return 0;	/* not reached */
+}
+
+void *
+__fmtflush(Fmt *f, void *t, int len)
+{
+	if(f->runes)
+		f->nfmt += (Rune*)t - (Rune*)f->to;
+	else
+		f->nfmt += (char*)t - (char *)f->to;
+	f->to = t;
+	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+		f->stop = f->to;
+		return nil;
+	}
+	return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width charactes
+ */
+int
+__fmtpad(Fmt *f, int n)
+{
+	char *t, *s;
+	int i;
+
+	t = (char*)f->to;
+	s = (char*)f->stop;
+	for(i = 0; i < n; i++)
+		FMTCHAR(f, t, s, ' ');
+	f->nfmt += t - (char *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+__rfmtpad(Fmt *f, int n)
+{
+	Rune *t, *s;
+	int i;
+
+	t = (Rune*)f->to;
+	s = (Rune*)f->stop;
+	for(i = 0; i < n; i++)
+		FMTRCHAR(f, t, s, ' ');
+	f->nfmt += t - (Rune *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+__fmtcpy(Fmt *f, const void *vm, int n, int sz)
+{
+	Rune *rt, *rs, r;
+	char *t, *s, *m, *me;
+	ulong fl;
+	int nc, w;
+
+	m = (char*)vm;
+	me = m + sz;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRCHAR(f, rt, rs, r);
+		}
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(m < me)
+			return -1;
+		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+			return -1;
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+__fmtrcpy(Fmt *f, const void *vm, int n)
+{
+	Rune r, *m, *me, *rt, *rs;
+	char *t, *s;
+	ulong fl;
+	int w;
+
+	m = (Rune*)vm;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(me = m + n; m < me; m++)
+			FMTRCHAR(f, rt, rs, *m);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+			return -1;
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(me = m + n; m < me; m++){
+			r = *m;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/* fmt out one character */
+int
+__charfmt(Fmt *f)
+{
+	char x[1];
+
+	x[0] = va_arg(f->args, int);
+	f->prec = 1;
+	return __fmtcpy(f, (const char*)x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+__runefmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = va_arg(f->args, int);
+	return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+	int p, i;
+	if(!s)
+		return __fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(i = 0; i < p; i++)
+			if(s[i] == 0)
+				break;
+		return __fmtcpy(f, s, utfnlen(s, i), i);	/* BUG?: won't print a partial rune at end */
+	}
+
+	return __fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+__strfmt(Fmt *f)
+{
+	char *s;
+
+	s = va_arg(f->args, char *);
+	return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+	Rune *e;
+	int n, p;
+
+	if(!s)
+		return __fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(n = 0; n < p; n++)
+			if(s[n] == 0)
+				break;
+	}else{
+		for(e = s; *e; e++)
+			;
+		n = e - s;
+	}
+	return __fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+__runesfmt(Fmt *f)
+{
+	Rune *s;
+
+	s = va_arg(f->args, Rune *);
+	return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+__percentfmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = f->r;
+	f->prec = 1;
+	return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* fmt an integer */
+int
+__ifmt(Fmt *f)
+{
+	char buf[70], *p, *conv;
+	uvlong vu;
+	ulong u;
+	int neg, base, i, n, fl, w, isv;
+
+	neg = 0;
+	fl = f->flags;
+	isv = 0;
+	vu = 0;
+	u = 0;
+	/*
+	 * Unsigned verbs
+	 */
+	switch(f->r){
+	case 'o':
+	case 'u':
+	case 'x':
+	case 'X':
+		fl |= FmtUnsigned;
+		break;
+	}
+	if(f->r == 'p'){
+		u = (ulong)va_arg(f->args, void*);
+		f->r = 'x';
+		fl |= FmtUnsigned;
+	}else if(fl & FmtVLong){
+		isv = 1;
+		if(fl & FmtUnsigned)
+			vu = va_arg(f->args, uvlong);
+		else
+			vu = va_arg(f->args, vlong);
+	}else if(fl & FmtLong){
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, ulong);
+		else
+			u = va_arg(f->args, long);
+	}else if(fl & FmtByte){
+		if(fl & FmtUnsigned)
+			u = (uchar)va_arg(f->args, int);
+		else
+			u = (char)va_arg(f->args, int);
+	}else if(fl & FmtShort){
+		if(fl & FmtUnsigned)
+			u = (ushort)va_arg(f->args, int);
+		else
+			u = (short)va_arg(f->args, int);
+	}else{
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, uint);
+		else
+			u = va_arg(f->args, int);
+	}
+	conv = "0123456789abcdef";
+	switch(f->r){
+	case 'd':
+	case 'i':
+		base = 10;
+		break;
+	case 'u':
+		base = 10;
+		break;
+	case 'x':
+		base = 16;
+		break;
+	case 'X':
+		base = 16;
+		conv = "0123456789ABCDEF";
+		break;
+	case 'b':
+		base = 2;
+		break;
+	case 'o':
+		base = 8;
+		break;
+	default:
+		return -1;
+	}
+	if(!(fl & FmtUnsigned)){
+		if(isv && (vlong)vu < 0){
+			vu = -(vlong)vu;
+			neg = 1;
+		}else if(!isv && (long)u < 0){
+			u = -(long)u;
+			neg = 1;
+		}
+	}else{
+		fl &= ~(FmtSign|FmtSpace);	/* no + for unsigned conversions */
+	}
+	p = buf + sizeof buf - 1;
+	n = 0;
+	if(isv){
+		while(vu){
+			i = vu % base;
+			vu /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}else{
+		while(u){
+			i = u % base;
+			u /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}
+	if(n == 0){
+		if(!(fl & FmtPrec) || f->prec != 0){
+			*p-- = '0';
+			n = 1;
+		}
+		fl &= ~FmtSharp;
+	}
+	for(w = f->prec; n < w && p > buf+3; n++)
+		*p-- = '0';
+	if(neg || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(fl & FmtSharp){
+		if(base == 16)
+			n += 2;
+		else if(base == 8){
+			if(p[1] == '0')
+				fl &= ~FmtSharp;
+			else
+				n++;
+		}
+	}
+	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
+		for(w = f->width; n < w && p > buf+3; n++)
+			*p-- = '0';
+		f->width = 0;
+	}
+	if(fl & FmtSharp){
+		if(base == 16)
+			*p-- = f->r;
+		if(base == 16 || base == 8)
+			*p-- = '0';
+	}
+	if(neg)
+		*p-- = '-';
+	else if(fl & FmtSign)
+		*p-- = '+';
+	else if(fl & FmtSpace)
+		*p-- = ' ';
+	f->flags &= ~FmtPrec;
+	return __fmtcpy(f, p + 1, n, n);
+}
+
+int
+__countfmt(Fmt *f)
+{
+	void *p;
+	ulong fl;
+
+	fl = f->flags;
+	p = va_arg(f->args, void*);
+	if(fl & FmtVLong){
+		*(vlong*)p = f->nfmt;
+	}else if(fl & FmtLong){
+		*(long*)p = f->nfmt;
+	}else if(fl & FmtByte){
+		*(char*)p = f->nfmt;
+	}else if(fl & FmtShort){
+		*(short*)p = f->nfmt;
+	}else{
+		*(int*)p = f->nfmt;
+	}
+	return 0;
+}
+
+int
+__flagfmt(Fmt *f)
+{
+	switch(f->r){
+	case ',':
+		f->flags |= FmtComma;
+		break;
+	case '-':
+		f->flags |= FmtLeft;
+		break;
+	case '+':
+		f->flags |= FmtSign;
+		break;
+	case '#':
+		f->flags |= FmtSharp;
+		break;
+	case ' ':
+		f->flags |= FmtSpace;
+		break;
+	case 'u':
+		f->flags |= FmtUnsigned;
+		break;
+	case 'h':
+		if(f->flags & FmtShort)
+			f->flags |= FmtByte;
+		f->flags |= FmtShort;
+		break;
+	case 'L':
+		f->flags |= FmtLDouble;
+		break;
+	case 'l':
+		if(f->flags & FmtLong)
+			f->flags |= FmtVLong;
+		f->flags |= FmtLong;
+		break;
+	}
+	return 1;
+}
+
+/* default error format */
+int
+__badfmt(Fmt *f)
+{
+	char x[3];
+
+	x[0] = '%';
+	x[1] = f->r;
+	x[2] = '%';
+	f->prec = 3;
+	__fmtcpy(f, (const void*)x, 3, 3);
+	return 0;
+}

+ 61 - 0
sys/src/ape/lib/fmt/dorfmt.c

@@ -0,0 +1,61 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+
+int
+dorfmt(Fmt *f, const Rune *fmt)
+{
+	Rune *rt, *rs;
+	int r;
+	char *t, *s;
+	int nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = f->to;
+			rs = f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRCHAR(f, rt, rs, r);
+			}
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = f->to;
+			s = f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRUNE(f, t, f->stop, r);
+			}
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = __fmtdispatch(f, fmt, 1);
+		if(fmt == nil)
+			return -1;
+	}
+	return 0;		/* not reached */
+}

+ 28 - 0
sys/src/ape/lib/fmt/errfmt.c

@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+__errfmt(Fmt *f)
+{
+	char *s;
+
+	s = strerror(errno);
+	return fmtstrcpy(f, s);
+}

+ 610 - 0
sys/src/ape/lib/fmt/fltfmt.c

@@ -0,0 +1,610 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+#include "nan.h"
+
+enum
+{
+	FDEFLT	= 6,
+	NSIGNIF	= 17
+};
+
+/*
+ * first few powers of 10, enough for about 1/2 of the
+ * total space for doubles.
+ */
+static double pows10[] =
+{
+	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,  
+	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,  
+	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,  
+	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,  
+	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,  
+	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,  
+	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,  
+	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,  
+	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,  
+	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,  
+	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, 
+	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 
+	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 
+	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 
+	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 
+	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 
+};
+
+static double
+pow10(int n)
+{
+	double d;
+	int neg;
+
+	neg = 0;
+	if(n < 0){
+		if(n < DBL_MIN_10_EXP){
+			return 0.;
+		}
+		neg = 1;
+		n = -n;
+	}else if(n > DBL_MAX_10_EXP){
+		return HUGE_VAL;
+	}
+	if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
+		d = pows10[n];
+	else{
+		d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+		for(;;){
+			n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
+			if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
+				d *= pows10[n];
+				break;
+			}
+			d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+		}
+	}
+	if(neg){
+		return 1./d;
+	}
+	return d;
+}
+
+static int
+xadd(char *a, int n, int v)
+{
+	char *b;
+	int c;
+
+	if(n < 0 || n >= NSIGNIF)
+		return 0;
+	for(b = a+n; b >= a; b--) {
+		c = *b + v;
+		if(c <= '9') {
+			*b = c;
+			return 0;
+		}
+		*b = '0';
+		v = 1;
+	}
+	*a = '1';	/* overflow adding */
+	return 1;
+}
+
+static int
+xsub(char *a, int n, int v)
+{
+	char *b;
+	int c;
+
+	for(b = a+n; b >= a; b--) {
+		c = *b - v;
+		if(c >= '0') {
+			*b = c;
+			return 0;
+		}
+		*b = '9';
+		v = 1;
+	}
+	*a = '9';	/* underflow subtracting */
+	return 1;
+}
+
+static void
+xaddexp(char *p, int e)
+{
+	char se[9];
+	int i;
+
+	*p++ = 'e';
+	if(e < 0) {
+		*p++ = '-';
+		e = -e;
+	}
+	i = 0;
+	while(e) {
+		se[i++] = e % 10 + '0';
+		e /= 10;
+	}
+	if(i == 0) {
+		*p++ = '0';
+	} else {
+		while(i > 0)
+			*p++ = se[--i];
+	}
+	*p++ = '\0';
+}
+
+static char*
+xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
+{
+	char s2[NSIGNIF+10];
+	double g, h;
+	int e, d, i;
+	int c2, sign, oerr;
+
+	if(chr == 'F')
+		chr = 'f';
+	if(prec > NSIGNIF)
+		prec = NSIGNIF;
+	if(prec < 0)
+		prec = 0;
+	if(__isNaN(f)) {
+		*decpt = 9999;
+		*rsign = 0;
+		strcpy(s1, "nan");
+		return &s1[3];
+	}
+	sign = 0;
+	if(f < 0) {
+		f = -f;
+		sign++;
+	}
+	*rsign = sign;
+	if(__isInf(f, 1) || __isInf(f, -1)) {
+		*decpt = 9999;
+		strcpy(s1, "inf");
+		return &s1[3];
+	}
+
+	e = 0;
+	g = f;
+	if(g != 0) {
+		frexp(f, &e);
+		e = (int)(e * .301029995664);
+		if(e >= -150 && e <= +150) {
+			d = 0;
+			h = f;
+		} else {
+			d = e/2;
+			h = f * pow10(-d);
+		}
+		g = h * pow10(d-e);
+		while(g < 1) {
+			e--;
+			g = h * pow10(d-e);
+		}
+		while(g >= 10) {
+			e++;
+			g = h * pow10(d-e);
+		}
+	}
+
+	/*
+	 * convert NSIGNIF digits and convert
+	 * back to get accuracy.
+	 */
+	for(i=0; i<NSIGNIF; i++) {
+		d = (int)g;
+		s1[i] = d + '0';
+		g = (g - d) * 10;
+	}
+	s1[i] = 0;
+
+	/*
+	 * try decimal rounding to eliminate 9s
+	 */
+	c2 = prec + 1;
+	if(chr == 'f')
+		c2 += e;
+	oerr = errno;
+	if(c2 >= NSIGNIF-2) {
+		strcpy(s2, s1);
+		d = e;
+		s1[NSIGNIF-2] = '0';
+		s1[NSIGNIF-1] = '0';
+		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+		g = fmtstrtod(s1, nil);
+		if(g == f)
+			goto found;
+		if(xadd(s1, NSIGNIF-3, 1)) {
+			e++;
+			xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+		}
+		g = fmtstrtod(s1, nil);
+		if(g == f)
+			goto found;
+		strcpy(s1, s2);
+		e = d;
+	}
+
+	/*
+	 * convert back so s1 gets exact answer
+	 */
+	for(d = 0; d < 10; d++) {
+		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+		g = fmtstrtod(s1, nil);
+		if(f > g) {
+			if(xadd(s1, NSIGNIF-1, 1))
+				e--;
+			continue;
+		}
+		if(f < g) {
+			if(xsub(s1, NSIGNIF-1, 1))
+				e++;
+			continue;
+		}
+		break;
+	}
+
+found:
+	errno = oerr;
+
+	/*
+	 * sign
+	 */
+	d = 0;
+	i = 0;
+
+	/*
+	 * round & adjust 'f' digits
+	 */
+	c2 = prec + 1;
+	if(chr == 'f'){
+		if(xadd(s1, c2+e, 5))
+			e++;
+		c2 += e;
+		if(c2 < 0){
+			c2 = 0;
+			e = -prec - 1;
+		}
+	}else{
+		if(xadd(s1, c2, 5))
+			e++;
+	}
+	if(c2 > NSIGNIF){
+		c2 = NSIGNIF;
+	}
+
+	*decpt = e + 1;
+
+	/*
+	 * terminate the converted digits
+	 */
+	s1[c2] = '\0';
+	return &s1[c2];
+}
+
+/*
+ * this function works like the standard dtoa, if you want it.
+ */
+#if 0
+static char*
+__dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
+{
+	static char s2[NSIGNIF + 10];
+	char *es;
+	int chr, prec;
+
+	switch(mode) {
+	/* like 'e' */
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+		chr = 'e';
+		break;
+	/* like 'g' */
+	case 0:
+	case 1:
+	default:
+		chr = 'g';
+		break;
+	/* like 'f' */
+	case 3:
+	case 5:
+	case 7:
+	case 9:
+		chr = 'f';
+		break;
+	}
+
+	if(chr != 'f' && ndigits){
+		ndigits--;
+	}
+	prec = ndigits;
+	if(prec > NSIGNIF)
+		prec = NSIGNIF;
+	if(ndigits == 0)
+		prec = NSIGNIF;
+	es = xdodtoa(s2, f, chr, prec, decpt, rsign);
+
+	/*
+	 * strip trailing 0
+	 */
+	for(; es > s2 + 1; es--){
+		if(es[-1] != '0'){
+			break;
+		}
+	}
+	*es = '\0';
+	if(rve != NULL)
+		*rve = es;
+	return s2;
+}
+#endif
+
+static int
+fmtzdotpad(Fmt *f, int n, int pt)
+{
+	char *t, *s;
+	int i;
+	Rune *rt, *rs;
+
+	if(f->runes){
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(i = 0; i < n; i++){
+			if(i == pt){
+				FMTRCHAR(f, rt, rs, '.');
+			}
+			FMTRCHAR(f, rt, rs, '0');
+		}
+		f->nfmt += rt - (Rune*)f->to;
+		f->to = rt;
+	}else{
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(i = 0; i < n; i++){
+			if(i == pt){
+				FMTCHAR(f, t, s, '.');
+			}
+			FMTCHAR(f, t, s, '0');
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+	}
+	return 0;
+}
+
+int
+__efgfmt(Fmt *fmt)
+{
+	double f;
+	char s1[NSIGNIF+10];
+	int e, d, n;
+	int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
+
+	f = va_arg(fmt->args, double);
+	prec = FDEFLT;
+	fl = fmt->flags;
+	fmt->flags = 0;
+	if(fl & FmtPrec)
+		prec = fmt->prec;
+	chr = fmt->r;
+	ucase = 0;
+	if(chr == 'E'){
+		chr = 'e';
+		ucase = 1;
+	}else if(chr == 'F'){
+		chr = 'f';
+		ucase = 1;
+	}else if(chr == 'G'){
+		chr = 'g';
+		ucase = 1;
+	}
+	if(prec > 0 && chr == 'g')
+		prec--;
+	if(prec < 0)
+		prec = 0;
+
+	xdodtoa(s1, f, chr, prec, &e, &sign);
+	e--;
+	if(*s1 == 'i' || *s1 == 'n'){
+		if(ucase){
+			if(*s1 == 'i'){
+				strcpy(s1, "INF");
+			}else{
+				strcpy(s1, "NAN");
+			}
+		}
+		fmt->flags = fl & (FmtWidth|FmtLeft);
+		return __fmtcpy(fmt, (const void*)s1, 3, 3);
+	}
+
+	/*
+	 * copy into final place
+	 * c1 digits of leading '0'
+	 * c2 digits from conversion
+	 * c3 digits of trailing '0'
+	 * c4 digits after '.'
+	 */
+	c1 = 0;
+	c2 = prec + 1;
+	c3 = 0;
+	c4 = prec;
+	switch(chr) {
+	default:
+		chr = 'e';
+		break;
+	case 'g':
+		/*
+		 * decide on 'e' of 'f' style convers
+		 */
+		if(e >= -4 && e <= prec) {
+			c1 = -e;
+			c4 = prec - e;
+			chr = 'h';	/* flag for 'f' style */
+		}
+		break;
+	case 'f':
+		c1 = -e;
+		if(c1 > prec)
+			c1 = prec + 1;
+		c2 += e;
+		break;
+	}
+
+	/*
+	 * clean up c1 c2 and c3
+	 */
+	if(c1 < 0)
+		c1 = 0;
+	if(c2 < 0)
+		c2 = 0;
+	if(c2 > NSIGNIF) {
+		c3 = c2-NSIGNIF;
+		c2 = NSIGNIF;
+	}
+
+	/*
+	 * trim trailing zeros for %g
+	 */
+	if(!(fl & FmtSharp)
+	&& (chr == 'g' || chr == 'h')){
+		if(c4 >= c3){
+			c4 -= c3;
+			c3 = 0;
+		}else{
+			c3 -= c4;
+			c4 = 0;
+		}
+		while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
+			c4--;
+			c2--;
+		}
+	}
+
+	/*
+	 * calculate the total length
+	 */
+	n = c1 + c2 + c3;
+	if(sign || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(c4 || (fl & FmtSharp)){
+		n++;
+	}
+	if(chr == 'e' || chr == 'g'){
+		n += 4;
+		if(e >= 100)
+			n++;
+	}
+
+	/*
+	 * pad to width if right justified
+	 */
+	if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
+		if(fl & FmtZero){
+			c1 += fmt->width - n;
+		}else{
+			if(__fmtpad(fmt, fmt->width - n) < 0){
+				return -1;
+			}
+		}
+	}
+
+	/*
+	 * sign
+	 */
+	d = 0;
+	if(sign)
+		d = '-';
+	else if(fl & FmtSign)
+		d = '+';
+	else if(fl & FmtSpace)
+		d = ' ';
+	if(d && fmtrune(fmt, d) < 0){
+		return -1;
+	}
+
+	/*
+	 * copy digits
+	 */
+	c4 = c1 + c2 + c3 - c4;
+	if(c1 > 0){
+		if(fmtzdotpad(fmt, c1, c4) < 0){
+			return -1;
+		}
+		c4 -= c1;
+	}
+	d = 0;
+	if(c4 >= 0 && c4 < c2){
+		if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
+			return -1;
+		d = c4;
+		c2 -= c4;
+		c4 = -1;
+	}
+	if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
+		return -1;
+	}
+	c4 -= c2;
+	if(c3 > 0){
+		if(fmtzdotpad(fmt, c3, c4) < 0){
+			return -1;
+		}
+		c4 -= c3;
+	}
+
+	/*
+	 * strip trailing '0' on g conv
+	 */
+	if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
+		return -1;
+	}
+	if(chr == 'e' || chr == 'g') {
+		d = 0;
+		if(ucase)
+			s1[d++] = 'E';
+		else
+			s1[d++] = 'e';
+		c1 = e;
+		if(c1 < 0) {
+			s1[d++] = '-';
+			c1 = -c1;
+		} else
+			s1[d++] = '+';
+		if(c1 >= 100) {
+			s1[d++] = c1/100 + '0';
+			c1 = c1%100;
+		}
+		s1[d++] = c1/10 + '0';
+		s1[d++] = c1%10 + '0';
+		if(__fmtcpy(fmt, s1, d, d) < 0){
+			return -1;
+		}
+	}
+	if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
+		if(__fmtpad(fmt, fmt->width - n) < 0){
+			return -1;
+		}
+	}
+	return 0;
+}

+ 221 - 0
sys/src/ape/lib/fmt/fmt.c

@@ -0,0 +1,221 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+enum
+{
+	Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+	int	c;
+	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+struct
+{
+	/* lock by calling __fmtlock, __fmtunlock */
+	int	nfmt;
+	Convfmt	fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+	' ',	__flagfmt,
+	'#',	__flagfmt,
+	'%',	__percentfmt,
+	'+',	__flagfmt,
+	',',	__flagfmt,
+	'-',	__flagfmt,
+	'C',	__runefmt,	/* Plan 9 addition */
+	'E',	__efgfmt,
+	'F',	__efgfmt,	/* ANSI only */
+	'G',	__efgfmt,
+	'L',	__flagfmt,	/* ANSI only */
+	'S',	__runesfmt,	/* Plan 9 addition */
+	'X',	__ifmt,
+	'b',	__ifmt,		/* Plan 9 addition */
+	'c',	__charfmt,
+	'd',	__ifmt,
+	'e',	__efgfmt,
+	'f',	__efgfmt,
+	'g',	__efgfmt,
+	'h',	__flagfmt,
+	'i',	__ifmt,		/* ANSI only */
+	'l',	__flagfmt,
+	'n',	__countfmt,
+	'o',	__ifmt,
+	'p',	__ifmt,
+	'r',	__errfmt,
+	's',	__strfmt,
+	'u',	__flagfmt,	/* in Unix, __ifmt */
+	'x',	__ifmt,
+	0,	nil,
+};
+
+
+int	(*fmtdoquote)(int);
+
+/*
+ * __fmtlock() must be set
+ */
+static int
+__fmtinstall(int c, Fmts f)
+{
+	Convfmt *p, *ep;
+
+	if(c<=0 || c>=65536)
+		return -1;
+	if(!f)
+		f = __badfmt;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			break;
+
+	if(p == &fmtalloc.fmt[Maxfmt])
+		return -1;
+
+	p->fmt = f;
+	if(p == ep){	/* installing a new format character */
+		fmtalloc.nfmt++;
+		p->c = c;
+	}
+
+	return 0;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+	int ret;
+
+	__fmtlock();
+	ret = __fmtinstall(c, f);
+	__fmtunlock();
+	return ret;
+}
+
+static Fmts
+fmtfmt(int c)
+{
+	Convfmt *p, *ep;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c){
+			while(p->fmt == nil)	/* loop until value is updated */
+				;
+			return p->fmt;
+		}
+
+	/* is this a predefined format char? */
+	__fmtlock();
+	for(p=knownfmt; p->c; p++)
+		if(p->c == c){
+			__fmtinstall(p->c, p->fmt);
+			__fmtunlock();
+			return p->fmt;
+		}
+	__fmtunlock();
+
+	return __badfmt;
+}
+
+void*
+__fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+	Rune rune, r;
+	int i, n;
+
+	f->flags = 0;
+	f->width = f->prec = 0;
+
+	for(;;){
+		if(isrunes){
+			r = *(Rune*)fmt;
+			fmt = (Rune*)fmt + 1;
+		}else{
+			fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
+			r = rune;
+		}
+		f->r = r;
+		switch(r){
+		case '\0':
+			return nil;
+		case '.':
+			f->flags |= FmtWidth|FmtPrec;
+			continue;
+		case '0':
+			if(!(f->flags & FmtWidth)){
+				f->flags |= FmtZero;
+				continue;
+			}
+			/* fall through */
+		case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			i = 0;
+			while(r >= '0' && r <= '9'){
+				i = i * 10 + r - '0';
+				if(isrunes){
+					r = *(Rune*)fmt;
+					fmt = (Rune*)fmt + 1;
+				}else{
+					r = *(char*)fmt;
+					fmt = (char*)fmt + 1;
+				}
+			}
+			if(isrunes)
+				fmt = (Rune*)fmt - 1;
+			else
+				fmt = (char*)fmt - 1;
+		numflag:
+			if(f->flags & FmtWidth){
+				f->flags |= FmtPrec;
+				f->prec = i;
+			}else{
+				f->flags |= FmtWidth;
+				f->width = i;
+			}
+			continue;
+		case '*':
+			i = va_arg(f->args, int);
+			if(i < 0){
+				/*
+				 * negative precision =>
+				 * ignore the precision.
+				 */
+				if(f->flags & FmtPrec){
+					f->flags &= ~FmtPrec;
+					f->prec = 0;
+					continue;
+				}
+				i = -i;
+				f->flags |= FmtLeft;
+			}
+			goto numflag;
+		}
+		n = (*fmtfmt(r))(f);
+		if(n < 0)
+			return nil;
+		if(n == 0)
+			return fmt;
+	}
+}

+ 121 - 0
sys/src/ape/lib/fmt/fmtdef.h

@@ -0,0 +1,121 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+#define uchar _fmtuchar
+#define ushort _fmtushort
+#define uint _fmtuint
+#define ulong _fmtulong
+#define vlong _fmtvlong
+#define uvlong _fmtuvlong
+
+#define USED(x) if(x);else
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
+#ifndef NOVLONGS
+typedef unsigned long long	uvlong;
+typedef long long		vlong;
+#endif
+
+#define nil		0	/* cannot be ((void*)0) because used for function pointers */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+	int	quoted;		/* if set, string must be quoted */
+	int	nrunesin;	/* number of input runes that can be accepted */
+	int	nbytesin;	/* number of input bytes that can be accepted */
+	int	nrunesout;	/* number of runes that will be generated */
+	int	nbytesout;	/* number of bytes that will be generated */
+};
+
+void	*__fmtflush(Fmt*, void*, int);
+void	*__fmtdispatch(Fmt*, void*, int);
+int	__floatfmt(Fmt*, double);
+int	__fmtpad(Fmt*, int);
+int	__rfmtpad(Fmt*, int);
+int	__fmtFdFlush(Fmt*);
+
+int	__efgfmt(Fmt*);
+int	__charfmt(Fmt*);
+int	__runefmt(Fmt*);
+int	__runesfmt(Fmt*);
+int	__countfmt(Fmt*);
+int	__flagfmt(Fmt*);
+int	__percentfmt(Fmt*);
+int	__ifmt(Fmt*);
+int	__strfmt(Fmt*);
+int	__badfmt(Fmt*);
+int	__fmtcpy(Fmt*, const void*, int, int);
+int	__fmtrcpy(Fmt*, const void*, int n);
+int	__errfmt(Fmt *f);
+
+double	__fmtpow10(int);
+
+void	__fmtlock(void);
+void	__fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (char*)s){\
+		t = __fmtflush(f, t, 1);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (Rune*)s){\
+		t = __fmtflush(f, t, sizeof(Rune));\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRUNE(f, t, s, r)\
+	do{\
+	Rune _rune;\
+	int _runelen;\
+	if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+		t = __fmtflush(f, t, _runelen);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	if(r < Runeself)\
+		*t++ = r;\
+	else{\
+		_rune = r;\
+		t += runetochar(t, &_rune);\
+	}\
+	}while(0)

+ 46 - 0
sys/src/ape/lib/fmt/fmtfd.c

@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * public routine for final flush of a formatting buffer
+ * to a file descriptor; returns total char count.
+ */
+int
+fmtfdflush(Fmt *f)
+{
+	if(__fmtFdFlush(f) <= 0)
+		return -1;
+	return f->nfmt;
+}
+
+/*
+ * initialize an output buffer for buffered printing
+ */
+int
+fmtfdinit(Fmt *f, int fd, char *buf, int size)
+{
+	f->runes = 0;
+	f->start = buf;
+	f->to = buf;
+	f->stop = buf + size;
+	f->flush = __fmtFdFlush;
+	f->farg = (void*)fd;
+	f->nfmt = 0;
+	return 0;
+}

+ 33 - 0
sys/src/ape/lib/fmt/fmtfdflush.c

@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <unistd.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * generic routine for flushing a formatting buffer
+ * to a file descriptor
+ */
+int
+__fmtFdFlush(Fmt *f)
+{
+	int n;
+
+	n = (char*)f->to - (char*)f->start;
+	if(n && write((int)f->farg, f->start, n) != n)
+		return 0;
+	f->to = f->start;
+	return 1;
+}

+ 28 - 0
sys/src/ape/lib/fmt/fmtlock.c

@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+void
+__fmtlock(void)
+{
+	;
+}
+
+void
+__fmtunlock(void)
+{
+	;
+}

+ 47 - 0
sys/src/ape/lib/fmt/fmtprint.c

@@ -0,0 +1,47 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va = f->args;
+	va_start(f->args, fmt);
+	n = dofmt(f, fmt);
+	va_end(f->args);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	f->args = va;
+	if(n >= 0)
+		return 0;
+	return n;
+}
+

+ 262 - 0
sys/src/ape/lib/fmt/fmtquote.c

@@ -0,0 +1,262 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by __quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ *	NUL in input
+ *	count exceeded in input
+ *	count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+	int w;
+	Rune c;
+
+	q->quoted = 0;
+	q->nbytesout = 0;
+	q->nrunesout = 0;
+	q->nbytesin = 0;
+	q->nrunesin = 0;
+	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+		if(nout < 2)
+			return;
+		q->quoted = 1;
+		q->nbytesout = 2;
+		q->nrunesout = 2;
+	}
+	for(; nin!=0; nin-=w){
+		if(s)
+			w = chartorune(&c, s);
+		else{
+			c = *r;
+			w = runelen(c);
+		}
+
+		if(c == '\0')
+			break;
+		if(runesout){
+			if(q->nrunesout+1 > nout)
+				break;
+		}else{
+			if(q->nbytesout+w > nout)
+				break;
+		}
+
+		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
+			if(!q->quoted){
+				if(runesout){
+					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
+						break;
+				}
+				q->nrunesout += 2;	/* include quotes */
+				q->nbytesout += 2;	/* include quotes */
+				q->quoted = 1;
+			}
+			if(c == '\'')	{
+				if(runesout){
+					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w > nout)	/* no room for quotes */
+						break;
+				}
+				q->nbytesout++;
+				q->nrunesout++;	/* quotes reproduce as two characters */
+			}
+		}
+
+		/* advance input */
+		if(s)
+			s += w;
+		else
+			r++;
+		q->nbytesin += w;
+		q->nrunesin++;
+
+		/* advance output */
+		q->nbytesout += w;
+		q->nrunesout++;
+	}
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+	Rune r, *rm, *rme;
+	char *t, *s, *m, *me;
+	Rune *rt, *rs;
+	ulong fl;
+	int nc, w;
+
+	m = sin;
+	me = m + q->nbytesin;
+	rm = rin;
+	rme = rm + q->nrunesin;
+
+	w = f->width;
+	fl = f->flags;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	t = (char*)f->to;
+	s = (char*)f->stop;
+	rt = (Rune*)f->to;
+	rs = (Rune*)f->stop;
+	if(f->runes)
+		FMTRCHAR(f, rt, rs, '\'');
+	else
+		FMTRUNE(f, t, s, '\'');
+	for(nc = q->nrunesin; nc > 0; nc--){
+		if(sin){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+		}else{
+			if(rm >= rme)
+				break;
+			r = *(uchar*)rm++;
+		}
+		if(f->runes){
+			FMTRCHAR(f, rt, rs, r);
+			if(r == '\'')
+				FMTRCHAR(f, rt, rs, r);
+		}else{
+			FMTRUNE(f, t, s, r);
+			if(r == '\'')
+				FMTRUNE(f, t, s, r);
+		}
+	}
+
+	if(f->runes){
+		FMTRCHAR(f, rt, rs, '\'');
+		USED(rs);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		FMTRUNE(f, t, s, '\'');
+		USED(s);
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+__quotestrfmt(int runesin, Fmt *f)
+{
+	int outlen;
+	Rune *r;
+	char *s;
+	Quoteinfo q;
+
+	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */
+	if(runesin){
+		r = va_arg(f->args, Rune *);
+		s = nil;
+	}else{
+		s = va_arg(f->args, char *);
+		r = nil;
+	}
+	if(!s && !r)
+		return __fmtcpy(f, (void*)"<nil>", 5, 5);
+
+	if(f->flush)
+		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
+	else if(f->runes)
+		outlen = (Rune*)f->stop - (Rune*)f->to;
+	else
+		outlen = (char*)f->stop - (char*)f->to;
+
+	__quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+	if(runesin){
+		if(!q.quoted)
+			return __fmtrcpy(f, r, q.nrunesin);
+		return qstrfmt(nil, r, &q, f);
+	}
+
+	if(!q.quoted)
+		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
+	return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+	return __quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+	return __quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+	fmtinstall('q', quotestrfmt);
+	fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+__needsquotes(char *s, int *quotelenp)
+{
+	Quoteinfo q;
+
+	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nbytesout;
+
+	return q.quoted;
+}
+
+int
+__runeneedsquotes(Rune *r, int *quotelenp)
+{
+	Quoteinfo q;
+
+	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nrunesout;
+
+	return q.quoted;
+}

+ 40 - 0
sys/src/ape/lib/fmt/fmtrune.c

@@ -0,0 +1,40 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+fmtrune(Fmt *f, int r)
+{
+	Rune *rt;
+	char *t;
+	int n;
+
+	if(f->runes){
+		rt = (Rune*)f->to;
+		FMTRCHAR(f, rt, f->stop, r);
+		f->to = rt;
+		n = 1;
+	}else{
+		t = (char*)f->to;
+		FMTRUNE(f, t, f->stop, r);
+		n = t - (char*)f->to;
+		f->to = t;
+	}
+	f->nfmt += n;
+	return 0;
+}

+ 65 - 0
sys/src/ape/lib/fmt/fmtstr.c

@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+	char *s;
+	int n;
+
+	n = (int)f->farg;
+	n += 256;
+	f->farg = (void*)n;
+	s = (char*)f->start;
+	f->start = realloc(s, n);
+	if(f->start == nil){
+		f->start = s;
+		return 0;
+	}
+	f->to = (char*)f->start + ((char*)f->to - s);
+	f->stop = (char*)f->start + n - 1;
+	return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+	int n;
+
+	f->runes = 0;
+	n = 32;
+	f->start = malloc(n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (char*)f->start + n - 1;
+	f->flush = fmtStrFlush;
+	f->farg = (void*)n;
+	f->nfmt = 0;
+	return 0;
+}
+
+char*
+fmtstrflush(Fmt *f)
+{
+	*(char*)f->to = '\0';
+	f->to = f->start;
+	return (char*)f->start;
+}

+ 46 - 0
sys/src/ape/lib/fmt/fmtvprint.c

@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va = f->args;
+	f->args = args;
+	n = dofmt(f, fmt);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	f->args = va;
+	if(n >= 0)
+		return 0;
+	return n;
+}
+

+ 28 - 0
sys/src/ape/lib/fmt/fprint.c

@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "utf.h"
+#include "fmt.h"
+
+int
+fprint(int fd, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(fd, fmt, args);
+	va_end(args);
+	return n;
+}

+ 59 - 0
sys/src/ape/lib/fmt/mkfile

@@ -0,0 +1,59 @@
+APE=/sys/src/ape
+<$APE/config
+
+LIB=/$objtype/lib/ape/libfmt.a
+
+NUM=\
+	charstod.$O\
+	pow10.$O\
+
+OFILES=\
+	dofmt.$O\
+	errfmt.$O\
+	fltfmt.$O\
+	fmt.$O\
+	fmtfd.$O\
+	fmtfdflush.$O\
+	fmtlock.$O\
+	fmtprint.$O\
+	fmtquote.$O\
+	fmtrune.$O\
+	fmtstr.$O\
+	fmtvprint.$O\
+	fprint.$O\
+	nan64.$O\
+	print.$O\
+	runefmtstr.$O\
+	runeseprint.$O\
+	runesmprint.$O\
+	runesnprint.$O\
+	runesprint.$O\
+	runevseprint.$O\
+	runevsmprint.$O\
+	runevsnprint.$O\
+	seprint.$O\
+	smprint.$O\
+	snprint.$O\
+	sprint.$O\
+	strtod.$O\
+	vfprint.$O\
+	vseprint.$O\
+	vsmprint.$O\
+	vsnprint.$O\
+	werrstr.$O\
+	$NUM\
+
+HFILES=\
+	fmtdef.h\
+	/sys/include/ape/fmt.h\
+
+</sys/src/cmd/mksyslib
+
+$NAN.$O: nan.h
+strtod.$O: nan.h
+
+test: $LIB test.$O
+	$CC -o test test.$O $LIB -L$PLAN9/lib -lutf
+
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_BSD_EXTENSION

+ 4 - 0
sys/src/ape/lib/fmt/nan.h

@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern int __isNaN(double);
+extern int __isInf(double, int);

+ 76 - 0
sys/src/ape/lib/fmt/nan64.c

@@ -0,0 +1,76 @@
+/*
+ * 64-bit IEEE not-a-number routines.
+ * This is big/little-endian portable assuming that 
+ * the 64-bit doubles and 64-bit integers have the
+ * same byte ordering.
+ */
+
+#include "nan.h"
+
+#ifdef __APPLE__
+#define _NEEDLL
+#endif
+
+typedef unsigned long long uvlong;
+typedef unsigned long ulong;
+
+#ifdef _NEEDLL
+static uvlong uvnan    = 0x7FF0000000000001LL;
+static uvlong uvinf    = 0x7FF0000000000000LL;
+static uvlong uvneginf = 0xFFF0000000000000LL;
+#else
+static uvlong uvnan    = 0x7FF0000000000001;
+static uvlong uvinf    = 0x7FF0000000000000;
+static uvlong uvneginf = 0xFFF0000000000000;
+#endif
+
+double
+__NaN(void)
+{
+	uvlong *p;
+
+	/* gcc complains about "return *(double*)&uvnan;" */
+	p = &uvnan;
+	return *(double*)p;
+}
+
+int
+__isNaN(double d)
+{
+	uvlong x;
+	double *p;
+
+	p = &d;
+	x = *(uvlong*)p;
+	return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
+}
+
+double
+__Inf(int sign)
+{
+	uvlong *p;
+
+	if(sign < 0)
+		p = &uvinf;
+	else
+		p = &uvneginf;
+	return *(double*)p;
+}
+
+int
+__isInf(double d, int sign)
+{
+	uvlong x;
+	double *p;
+
+	p = &d;
+	x = *(uvlong*)p;
+	if(sign == 0)
+		return x==uvinf || x==uvneginf;
+	else if(sign > 0)
+		return x==uvinf;
+	else
+		return x==uvneginf;
+}
+
+

+ 57 - 0
sys/src/ape/lib/fmt/pow10.c

@@ -0,0 +1,57 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+
+static
+double	tab[] =
+{
+	1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
+	1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
+	1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
+	1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
+	1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
+	1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
+	1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
+};
+
+double
+__fmtpow10(int n)
+{
+	int m;
+
+	if(n < 0) {
+		n = -n;
+		if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+			return 1/tab[n];
+		m = n/2;
+		return __fmtpow10(-m) * __fmtpow10(m-n);
+	}
+	if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+		return tab[n];
+	m = n/2;
+	return __fmtpow10(m) * __fmtpow10(n-m);
+}

+ 28 - 0
sys/src/ape/lib/fmt/print.c

@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "utf.h"
+#include "fmt.h"
+
+int
+print(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(1, fmt, args);
+	va_end(args);
+	return n;
+}

+ 65 - 0
sys/src/ape/lib/fmt/runefmtstr.c

@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+static int
+runeFmtStrFlush(Fmt *f)
+{
+	Rune *s;
+	int n;
+
+	n = (int)f->farg;
+	n += 256;
+	f->farg = (void*)n;
+	s = (Rune*)f->start;
+	f->start = realloc(s, sizeof(Rune)*n);
+	if(f->start == nil){
+		f->start = s;
+		return 0;
+	}
+	f->to = (Rune*)f->start + ((Rune*)f->to - s);
+	f->stop = (Rune*)f->start + n - 1;
+	return 1;
+}
+
+int
+runefmtstrinit(Fmt *f)
+{
+	int n;
+
+	f->runes = 1;
+	n = 32;
+	f->start = malloc(sizeof(Rune)*n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (Rune*)f->start + n - 1;
+	f->flush = runeFmtStrFlush;
+	f->farg = (void*)n;
+	f->nfmt = 0;
+	return 0;
+}
+
+Rune*
+runefmtstrflush(Fmt *f)
+{
+	*(Rune*)f->to = '\0';
+	f->to = f->start;
+	return f->start;
+}

+ 30 - 0
sys/src/ape/lib/fmt/runeseprint.c

@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+Rune*
+runeseprint(Rune *buf, Rune *e, char *fmt, ...)
+{
+	Rune *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = runevseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}

+ 30 - 0
sys/src/ape/lib/fmt/runesmprint.c

@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+Rune*
+runesmprint(char *fmt, ...)
+{
+	va_list args;
+	Rune *p;
+
+	va_start(args, fmt);
+	p = runevsmprint(fmt, args);
+	va_end(args);
+	return p;
+}

+ 31 - 0
sys/src/ape/lib/fmt/runesnprint.c

@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+runesnprint(Rune *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = runevsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+

+ 30 - 0
sys/src/ape/lib/fmt/runesprint.c

@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+runesprint(Rune *buf, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = runevsnprint(buf, 256, fmt, args);
+	va_end(args);
+	return n;
+}

+ 39 - 0
sys/src/ape/lib/fmt/runevseprint.c

@@ -0,0 +1,39 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+Rune*
+runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 1;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(Rune*)f.to = '\0';
+	return (Rune*)f.to;
+}
+

+ 37 - 0
sys/src/ape/lib/fmt/runevsmprint.c

@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * print into an allocated string buffer
+ */
+Rune*
+runevsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(runefmtstrinit(&f) < 0)
+		return nil;
+	f.args = args;
+	n = dofmt(&f, fmt);
+	if(n < 0)
+		return nil;
+	*(Rune*)f.to = '\0';
+	return (Rune*)f.start;
+}

+ 38 - 0
sys/src/ape/lib/fmt/runevsnprint.c

@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+runevsnprint(Rune *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 1;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(Rune*)f.to = '\0';
+	return (Rune*)f.to - buf;
+}

+ 27 - 0
sys/src/ape/lib/fmt/seprint.c

@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+	char *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = vseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}

+ 27 - 0
sys/src/ape/lib/fmt/smprint.c

@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+char*
+smprint(char *fmt, ...)
+{
+	va_list args;
+	char *p;
+
+	va_start(args, fmt);
+	p = vsmprint(fmt, args);
+	va_end(args);
+	return p;
+}

+ 28 - 0
sys/src/ape/lib/fmt/snprint.c

@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+

+ 27 - 0
sys/src/ape/lib/fmt/sprint.c

@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, 65536, fmt, args);	/* big number, but sprint is deprecated anyway */
+	va_end(args);
+	return n;
+}

+ 539 - 0
sys/src/ape/lib/fmt/strtod.c

@@ -0,0 +1,539 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "fmt.h"
+#include "nan.h"
+
+#ifndef nelem
+#define nelem(x)	(sizeof(x)/sizeof *(x))
+#endif
+#define nil ((void*)0)
+#define ulong _fmtulong
+typedef unsigned long ulong;
+
+static ulong
+umuldiv(ulong a, ulong b, ulong c)
+{
+	double d;
+
+	d = ((double)a * (double)b) / (double)c;
+	if(d >= 4294967295.)
+		d = 4294967295.;
+	return (ulong)d;
+}
+
+/*
+ * This routine will convert to arbitrary precision
+ * floating point entirely in multi-precision fixed.
+ * The answer is the closest floating point number to
+ * the given decimal number. Exactly half way are
+ * rounded ala ieee rules.
+ * Method is to scale input decimal between .500 and .999...
+ * with external power of 2, then binary search for the
+ * closest mantissa to this decimal number.
+ * Nmant is is the required precision. (53 for ieee dp)
+ * Nbits is the max number of bits/word. (must be <= 28)
+ * Prec is calculated - the number of words of fixed mantissa.
+ */
+enum
+{
+	Nbits	= 28,				/* bits safely represented in a ulong */
+	Nmant	= 53,				/* bits of precision required */
+	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
+	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
+	Ndig	= 1500,
+	One	= (ulong)(1<<Nbits),
+	Half	= (ulong)(One>>1),
+	Maxe	= 310,
+
+	Fsign	= 1<<0,		/* found - */
+	Fesign	= 1<<1,		/* found e- */
+	Fdpoint	= 1<<2,		/* found . */
+
+	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
+	S1,			/* _+		#S2	.S3 */
+	S2,			/* _+#		#S2	.S4	eS5 */
+	S3,			/* _+.		#S4 */
+	S4,			/* _+#.#	#S4	eS5 */
+	S5,			/* _+#.#e	+S6	#S7 */
+	S6,			/* _+#.#e+	#S7 */
+	S7,			/* _+#.#e+#	#S7 */
+};
+
+static	int	xcmp(char*, char*);
+static	int	fpcmp(char*, ulong*);
+static	void	frnorm(ulong*);
+static	void	divascii(char*, int*, int*, int*);
+static	void	mulascii(char*, int*, int*, int*);
+
+typedef	struct	Tab	Tab;
+struct	Tab
+{
+	int	bp;
+	int	siz;
+	char*	cmp;
+};
+
+double
+fmtstrtod(const char *as, char **aas)
+{
+	int na, ex, dp, bp, c, i, flag, state;
+	ulong low[Prec], hig[Prec], mid[Prec];
+	double d;
+	char *s, a[Ndig];
+
+	flag = 0;	/* Fsign, Fesign, Fdpoint */
+	na = 0;		/* number of digits of a[] */
+	dp = 0;		/* na of decimal point */
+	ex = 0;		/* exonent */
+
+	state = S0;
+	for(s=(char*)as;; s++) {
+		c = *s;
+		if(c >= '0' && c <= '9') {
+			switch(state) {
+			case S0:
+			case S1:
+			case S2:
+				state = S2;
+				break;
+			case S3:
+			case S4:
+				state = S4;
+				break;
+
+			case S5:
+			case S6:
+			case S7:
+				state = S7;
+				ex = ex*10 + (c-'0');
+				continue;
+			}
+			if(na == 0 && c == '0') {
+				dp--;
+				continue;
+			}
+			if(na < Ndig-50)
+				a[na++] = c;
+			continue;
+		}
+		switch(c) {
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			if(state == S0)
+				continue;
+			break;
+		case '-':
+			if(state == S0)
+				flag |= Fsign;
+			else
+				flag |= Fesign;
+		case '+':
+			if(state == S0)
+				state = S1;
+			else
+			if(state == S5)
+				state = S6;
+			else
+				break;	/* syntax */
+			continue;
+		case '.':
+			flag |= Fdpoint;
+			dp = na;
+			if(state == S0 || state == S1) {
+				state = S3;
+				continue;
+			}
+			if(state == S2) {
+				state = S4;
+				continue;
+			}
+			break;
+		case 'e':
+		case 'E':
+			if(state == S2 || state == S4) {
+				state = S5;
+				continue;
+			}
+			break;
+		}
+		break;
+	}
+
+	/*
+	 * clean up return char-pointer
+	 */
+	switch(state) {
+	case S0:
+		if(xcmp(s, "nan") == 0) {
+			if(aas != nil)
+				*aas = s+3;
+			goto retnan;
+		}
+	case S1:
+		if(xcmp(s, "infinity") == 0) {
+			if(aas != nil)
+				*aas = s+8;
+			goto retinf;
+		}
+		if(xcmp(s, "inf") == 0) {
+			if(aas != nil)
+				*aas = s+3;
+			goto retinf;
+		}
+	case S3:
+		if(aas != nil)
+			*aas = (char*)as;
+		goto ret0;	/* no digits found */
+	case S6:
+		s--;		/* back over +- */
+	case S5:
+		s--;		/* back over e */
+		break;
+	}
+	if(aas != nil)
+		*aas = s;
+
+	if(flag & Fdpoint)
+	while(na > 0 && a[na-1] == '0')
+		na--;
+	if(na == 0)
+		goto ret0;	/* zero */
+	a[na] = 0;
+	if(!(flag & Fdpoint))
+		dp = na;
+	if(flag & Fesign)
+		ex = -ex;
+	dp += ex;
+	if(dp < -Maxe){
+		errno = ERANGE;
+		goto ret0;	/* underflow by exp */
+	} else
+	if(dp > +Maxe)
+		goto retinf;	/* overflow by exp */
+
+	/*
+	 * normalize the decimal ascii number
+	 * to range .[5-9][0-9]* e0
+	 */
+	bp = 0;		/* binary exponent */
+	while(dp > 0)
+		divascii(a, &na, &dp, &bp);
+	while(dp < 0 || a[0] < '5')
+		mulascii(a, &na, &dp, &bp);
+
+	/* close approx by naive conversion */
+	mid[0] = 0;
+	mid[1] = 1;
+	for(i=0; c=a[i]; i++) {
+		mid[0] = mid[0]*10 + (c-'0');
+		mid[1] = mid[1]*10;
+		if(i >= 8)
+			break;
+	}
+	low[0] = umuldiv(mid[0], One, mid[1]);
+	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
+	for(i=1; i<Prec; i++) {
+		low[i] = 0;
+		hig[i] = One-1;
+	}
+
+	/* binary search for closest mantissa */
+	for(;;) {
+		/* mid = (hig + low) / 2 */
+		c = 0;
+		for(i=0; i<Prec; i++) {
+			mid[i] = hig[i] + low[i];
+			if(c)
+				mid[i] += One;
+			c = mid[i] & 1;
+			mid[i] >>= 1;
+		}
+		frnorm(mid);
+
+		/* compare */
+		c = fpcmp(a, mid);
+		if(c > 0) {
+			c = 1;
+			for(i=0; i<Prec; i++)
+				if(low[i] != mid[i]) {
+					c = 0;
+					low[i] = mid[i];
+				}
+			if(c)
+				break;	/* between mid and hig */
+			continue;
+		}
+		if(c < 0) {
+			for(i=0; i<Prec; i++)
+				hig[i] = mid[i];
+			continue;
+		}
+
+		/* only hard part is if even/odd roundings wants to go up */
+		c = mid[Prec-1] & (Sigbit-1);
+		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
+			mid[Prec-1] -= c;
+		break;	/* exactly mid */
+	}
+
+	/* normal rounding applies */
+	c = mid[Prec-1] & (Sigbit-1);
+	mid[Prec-1] -= c;
+	if(c >= Sigbit/2) {
+		mid[Prec-1] += Sigbit;
+		frnorm(mid);
+	}
+	goto out;
+
+ret0:
+	return 0;
+
+retnan:
+	return __NaN();
+
+retinf:
+	/*
+	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
+	errno = ERANGE;
+	if(flag & Fsign)
+		return -HUGE_VAL;
+	return HUGE_VAL;
+
+out:
+	d = 0;
+	for(i=0; i<Prec; i++)
+		d = d*One + mid[i];
+	if(flag & Fsign)
+		d = -d;
+	d = ldexp(d, bp - Prec*Nbits);
+	if(d == 0){	/* underflow */
+		errno = ERANGE;
+	}
+	return d;
+}
+
+static void
+frnorm(ulong *f)
+{
+	int i, c;
+
+	c = 0;
+	for(i=Prec-1; i>0; i--) {
+		f[i] += c;
+		c = f[i] >> Nbits;
+		f[i] &= One-1;
+	}
+	f[0] += c;
+}
+
+static int
+fpcmp(char *a, ulong* f)
+{
+	ulong tf[Prec];
+	int i, d, c;
+
+	for(i=0; i<Prec; i++)
+		tf[i] = f[i];
+
+	for(;;) {
+		/* tf *= 10 */
+		for(i=0; i<Prec; i++)
+			tf[i] = tf[i]*10;
+		frnorm(tf);
+		d = (tf[0] >> Nbits) + '0';
+		tf[0] &= One-1;
+
+		/* compare next digit */
+		c = *a;
+		if(c == 0) {
+			if('0' < d)
+				return -1;
+			if(tf[0] != 0)
+				goto cont;
+			for(i=1; i<Prec; i++)
+				if(tf[i] != 0)
+					goto cont;
+			return 0;
+		}
+		if(c > d)
+			return +1;
+		if(c < d)
+			return -1;
+		a++;
+	cont:;
+	}
+	return 0;
+}
+
+static void
+divby(char *a, int *na, int b)
+{
+	int n, c;
+	char *p;
+
+	p = a;
+	n = 0;
+	while(n>>b == 0) {
+		c = *a++;
+		if(c == 0) {
+			while(n) {
+				c = n*10;
+				if(c>>b)
+					break;
+				n = c;
+			}
+			goto xx;
+		}
+		n = n*10 + c-'0';
+		(*na)--;
+	}
+	for(;;) {
+		c = n>>b;
+		n -= c<<b;
+		*p++ = c + '0';
+		c = *a++;
+		if(c == 0)
+			break;
+		n = n*10 + c-'0';
+	}
+	(*na)++;
+xx:
+	while(n) {
+		n = n*10;
+		c = n>>b;
+		n -= c<<b;
+		*p++ = c + '0';
+		(*na)++;
+	}
+	*p = 0;
+}
+
+static	Tab	tab1[] =
+{
+	 1,  0, "",
+	 3,  1, "7",
+	 6,  2, "63",
+	 9,  3, "511",
+	13,  4, "8191",
+	16,  5, "65535",
+	19,  6, "524287",
+	23,  7, "8388607",
+	26,  8, "67108863",
+	27,  9, "134217727",
+};
+
+static void
+divascii(char *a, int *na, int *dp, int *bp)
+{
+	int b, d;
+	Tab *t;
+
+	d = *dp;
+	if(d >= (int)(nelem(tab1)))
+		d = (int)(nelem(tab1))-1;
+	t = tab1 + d;
+	b = t->bp;
+	if(memcmp(a, t->cmp, t->siz) > 0)
+		d--;
+	*dp -= d;
+	*bp += b;
+	divby(a, na, b);
+}
+
+static void
+mulby(char *a, char *p, char *q, int b)
+{
+	int n, c;
+
+	n = 0;
+	*p = 0;
+	for(;;) {
+		q--;
+		if(q < a)
+			break;
+		c = *q - '0';
+		c = (c<<b) + n;
+		n = c/10;
+		c -= n*10;
+		p--;
+		*p = c + '0';
+	}
+	while(n) {
+		c = n;
+		n = c/10;
+		c -= n*10;
+		p--;
+		*p = c + '0';
+	}
+}
+
+static	Tab	tab2[] =
+{
+	 1,  1, "",				/* dp = 0-0 */
+	 3,  3, "125",
+	 6,  5, "15625",
+	 9,  7, "1953125",
+	13, 10, "1220703125",
+	16, 12, "152587890625",
+	19, 14, "19073486328125",
+	23, 17, "11920928955078125",
+	26, 19, "1490116119384765625",
+	27, 19, "7450580596923828125",		/* dp 8-9 */
+};
+
+static void
+mulascii(char *a, int *na, int *dp, int *bp)
+{
+	char *p;
+	int d, b;
+	Tab *t;
+
+	d = -*dp;
+	if(d >= (int)(nelem(tab2)))
+		d = (int)(nelem(tab2))-1;
+	t = tab2 + d;
+	b = t->bp;
+	if(memcmp(a, t->cmp, t->siz) < 0)
+		d--;
+	p = a + *na;
+	*bp -= b;
+	*dp += d;
+	*na += d;
+	mulby(a, p+d, p, b);
+}
+
+static int
+xcmp(char *a, char *b)
+{
+	int c1, c2;
+
+	while(c1 = *b++) {
+		c2 = *a++;
+		if(isupper(c2))
+			c2 = tolower(c2);
+		if(c1 != c2)
+			return 1;
+	}
+	return 0;
+}

+ 4 - 0
sys/src/ape/lib/fmt/strtod.h

@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern double __isNaN(double);
+extern double __isInf(double, int);

+ 39 - 0
sys/src/ape/lib/fmt/test.c

@@ -0,0 +1,39 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <utf.h>
+#include "fmt.h"
+
+int
+main(int argc, char *argv[])
+{
+	quotefmtinstall();
+	print("hello world\n");
+	print("x: %x\n", 0x87654321);
+	print("u: %u\n", 0x87654321);
+	print("d: %d\n", 0x87654321);
+	print("s: %s\n", "hi there");
+	print("q: %q\n", "hi i'm here");
+	print("c: %c\n", '!');
+	print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("smiley: %C\n", (Rune)0x263a);
+	print("%g %.18\n", 2e25, 2e25);
+	print("%2.18g\n", 1.0);
+	print("%f\n", 3.1415927/4);
+	print("%d\n", 23);
+	print("%i\n", 23);
+	return 0;
+}

+ 31 - 0
sys/src/ape/lib/fmt/vfprint.c

@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+vfprint(int fd, char *fmt, va_list args)
+{
+	Fmt f;
+	char buf[256];
+	int n;
+
+	fmtfdinit(&f, fd, buf, sizeof(buf));
+	f.args = args;
+	n = dofmt(&f, fmt);
+	if(n > 0 && __fmtFdFlush(&f) == 0)
+		return -1;
+	return n;
+}

+ 37 - 0
sys/src/ape/lib/fmt/vseprint.c

@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = 0;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(char*)f.to = '\0';
+	return (char*)f.to;
+}
+

+ 36 - 0
sys/src/ape/lib/fmt/vsmprint.c

@@ -0,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(fmtstrinit(&f) < 0)
+		return nil;
+	f.args = args;
+	n = dofmt(&f, fmt);
+	if(n < 0)
+		return nil;
+	*(char*)f.to = '\0';
+	return (char*)f.start;
+}

+ 37 - 0
sys/src/ape/lib/fmt/vsnprint.c

@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = 0;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(char*)f.to = '\0';
+	return (char*)f.to - buf;
+}

+ 16 - 0
sys/src/ape/lib/fmt/werrstr.c

@@ -0,0 +1,16 @@
+#include <stdarg.h>
+#include <errno.h>
+#include "fmt.h"
+
+extern char _plan9err[128];
+
+void
+werrstr(const char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	snprint(_plan9err, sizeof _plan9err, fmt, arg);
+	va_end(arg);
+	errno = EPLAN9;
+}

+ 1 - 1
sys/src/ape/lib/mkfile

@@ -1,6 +1,6 @@
 </$objtype/mkfile
 </$objtype/mkfile
 
 
-DIRS=9 ap bsd l net regexp v
+DIRS=9 ap bsd draw fmt l net regexp utf v
 
 
 none:V:
 none:V:
 	echo mk all, install, installall, clean, or nuke
 	echo mk all, install, installall, clean, or nuke

+ 17 - 0
sys/src/ape/lib/utf/lib9.h

@@ -0,0 +1,17 @@
+#include <string.h>
+#include "utf.h"
+
+#define nil ((void*)0)
+
+#define uchar _fmtuchar
+#define ushort _fmtushort
+#define uint _fmtuint
+#define ulong _fmtulong
+#define vlong _fmtvlong
+#define uvlong _fmtuvlong
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+

+ 37 - 0
sys/src/ape/lib/utf/mkfile

@@ -0,0 +1,37 @@
+APE=/sys/src/ape
+<$APE/config
+
+LIB=/$objtype/lib/ape/libutf.a
+
+OFILES=\
+	rune.$O\
+	runestrcat.$O\
+	runestrchr.$O\
+	runestrcmp.$O\
+	runestrcpy.$O\
+	runestrdup.$O\
+	runestrlen.$O\
+	runestrecpy.$O\
+	runestrncat.$O\
+	runestrncmp.$O\
+	runestrncpy.$O\
+	runestrrchr.$O\
+	runestrstr.$O\
+	runetype.$O\
+	utfecpy.$O\
+	utflen.$O\
+	utfnlen.$O\
+	utfrrune.$O\
+	utfrune.$O\
+	utfutf.$O\
+
+HFILES=\
+	/sys/include/ape/utf.h\
+
+UPDATE=\
+	mkfile\
+	${OFILES:%.$O=%.c}\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_BSD_EXTENSION

+ 177 - 0
sys/src/ape/lib/utf/rune.c

@@ -0,0 +1,177 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+enum
+{
+	Bit1	= 7,
+	Bitx	= 6,
+	Bit2	= 5,
+	Bit3	= 4,
+	Bit4	= 3,
+
+	T1	= ((1<<(Bit1+1))-1) ^ 0xFF,	/* 0000 0000 */
+	Tx	= ((1<<(Bitx+1))-1) ^ 0xFF,	/* 1000 0000 */
+	T2	= ((1<<(Bit2+1))-1) ^ 0xFF,	/* 1100 0000 */
+	T3	= ((1<<(Bit3+1))-1) ^ 0xFF,	/* 1110 0000 */
+	T4	= ((1<<(Bit4+1))-1) ^ 0xFF,	/* 1111 0000 */
+
+	Rune1	= (1<<(Bit1+0*Bitx))-1,		/* 0000 0000 0111 1111 */
+	Rune2	= (1<<(Bit2+1*Bitx))-1,		/* 0000 0111 1111 1111 */
+	Rune3	= (1<<(Bit3+2*Bitx))-1,		/* 1111 1111 1111 1111 */
+
+	Maskx	= (1<<Bitx)-1,			/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,			/* 1100 0000 */
+
+	Bad	= Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+	int c, c1, c2;
+	long l;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => T1
+	 */
+	c = *(uchar*)str;
+	if(c < Tx) {
+		*rune = c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	c1 = *(uchar*)(str+1) ^ Tx;
+	if(c1 & Testx)
+		goto bad;
+	if(c < T3) {
+		if(c < T2)
+			goto bad;
+		l = ((c << Bitx) | c1) & Rune2;
+		if(l <= Rune1)
+			goto bad;
+		*rune = l;
+		return 2;
+	}
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	c2 = *(uchar*)(str+2) ^ Tx;
+	if(c2 & Testx)
+		goto bad;
+	if(c < T4) {
+		l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+		if(l <= Rune2)
+			goto bad;
+		*rune = l;
+		return 3;
+	}
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+	long c;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 */
+	c = *rune;
+	if(c <= Rune1) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	if(c <= Rune2) {
+		str[0] = T2 | (c >> 1*Bitx);
+		str[1] = Tx | (c & Maskx);
+		return 2;
+	}
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	str[0] = T3 |  (c >> 2*Bitx);
+	str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+	str[2] = Tx |  (c & Maskx);
+	return 3;
+}
+
+int
+runelen(long c)
+{
+	Rune rune;
+	char str[10];
+
+	rune = c;
+	return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+	int nb, c;
+
+	nb = 0;
+	while(nrune--) {
+		c = *r++;
+		if(c <= Rune1)
+			nb++;
+		else
+		if(c <= Rune2)
+			nb += 2;
+		else
+			nb += 3;
+	}
+	return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+	int c;
+
+	if(n > 0) {
+		c = *(uchar*)str;
+		if(c < Tx)
+			return 1;
+		if(n > 1)
+			if(c < T3 || n > 2)
+				return 1;
+	}
+	return 0;
+}

+ 25 - 0
sys/src/ape/lib/utf/runestrcat.c

@@ -0,0 +1,25 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrcat(Rune *s1, Rune *s2)
+{
+
+	runestrcpy(runestrchr(s1, 0), s2);
+	return s1;
+}

+ 35 - 0
sys/src/ape/lib/utf/runestrchr.c

@@ -0,0 +1,35 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrchr(Rune *s, Rune c)
+{
+	Rune c0 = c;
+	Rune c1;
+
+	if(c == 0) {
+		while(*s++)
+			;
+		return s-1;
+	}
+
+	while(c1 = *s++)
+		if(c1 == c0)
+			return s-1;
+	return 0;
+}

+ 35 - 0
sys/src/ape/lib/utf/runestrcmp.c

@@ -0,0 +1,35 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+runestrcmp(Rune *s1, Rune *s2)
+{
+	Rune c1, c2;
+
+	for(;;) {
+		c1 = *s1++;
+		c2 = *s2++;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			return 0;
+	}
+}

+ 28 - 0
sys/src/ape/lib/utf/runestrcpy.c

@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrcpy(Rune *s1, Rune *s2)
+{
+	Rune *os1;
+
+	os1 = s1;
+	while(*s1++ = *s2++)
+		;
+	return os1;
+}

+ 30 - 0
sys/src/ape/lib/utf/runestrdup.c

@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrdup(Rune *s) 
+{  
+	Rune *ns;
+
+	ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
+	if(ns == 0)
+		return 0;
+
+	return runestrcpy(ns, s);
+}

+ 32 - 0
sys/src/ape/lib/utf/runestrecpy.c

@@ -0,0 +1,32 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrecpy(Rune *s1, Rune *es1, Rune *s2)
+{
+	if(s1 >= es1)
+		return s1;
+
+	while(*s1++ = *s2++){
+		if(s1 == es1){
+			*--s1 = '\0';
+			break;
+		}
+	}
+	return s1;
+}

+ 24 - 0
sys/src/ape/lib/utf/runestrlen.c

@@ -0,0 +1,24 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+long
+runestrlen(Rune *s)
+{
+
+	return runestrchr(s, 0) - s;
+}

+ 32 - 0
sys/src/ape/lib/utf/runestrncat.c

@@ -0,0 +1,32 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrncat(Rune *s1, Rune *s2, long n)
+{
+	Rune *os1;
+
+	os1 = s1;
+	s1 = runestrchr(s1, 0);
+	while(*s1++ = *s2++)
+		if(--n < 0) {
+			s1[-1] = 0;
+			break;
+		}
+	return os1;
+}

+ 37 - 0
sys/src/ape/lib/utf/runestrncmp.c

@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+runestrncmp(Rune *s1, Rune *s2, long n)
+{
+	Rune c1, c2;
+
+	while(n > 0) {
+		c1 = *s1++;
+		c2 = *s2++;
+		n--;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			break;
+	}
+	return 0;
+}

+ 33 - 0
sys/src/ape/lib/utf/runestrncpy.c

@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrncpy(Rune *s1, Rune *s2, long n)
+{
+	int i;
+	Rune *os1;
+
+	os1 = s1;
+	for(i = 0; i < n; i++)
+		if((*s1++ = *s2++) == 0) {
+			while(++i < n)
+				*s1++ = 0;
+			return os1;
+		}
+	return os1;
+}

+ 30 - 0
sys/src/ape/lib/utf/runestrrchr.c

@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrrchr(Rune *s, Rune c)
+{
+	Rune *r;
+
+	if(c == 0)
+		return runestrchr(s, 0);
+	r = 0;
+	while(s = runestrchr(s, c))
+		r = s++;
+	return r;
+}

+ 44 - 0
sys/src/ape/lib/utf/runestrstr.c

@@ -0,0 +1,44 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+Rune*
+runestrstr(Rune *s1, Rune *s2)
+{
+	Rune *p, *pa, *pb;
+	int c0, c;
+
+	c0 = *s2;
+	if(c0 == 0)
+		return s1;
+	s2++;
+	for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) {
+		pa = p;
+		for(pb=s2;; pb++) {
+			c = *pb;
+			if(c == 0)
+				return p;
+			if(c != *++pa)
+				break;
+		}
+	}
+	return 0;
+}

+ 1152 - 0
sys/src/ape/lib/utf/runetype.c

@@ -0,0 +1,1152 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+/*
+ * alpha ranges -
+ *	only covers ranges not in lower||upper
+ */
+static
+Rune	__alpha2[] =
+{
+	0x00d8,	0x00f6,	/* Ø - ö */
+	0x00f8,	0x01f5,	/* ø - ǵ */
+	0x0250,	0x02a8,	/* ɐ - ʨ */
+	0x038e,	0x03a1,	/* Ύ - Ρ */
+	0x03a3,	0x03ce,	/* Σ - ώ */
+	0x03d0,	0x03d6,	/* ϐ - ϖ */
+	0x03e2,	0x03f3,	/* Ϣ - ϳ */
+	0x0490,	0x04c4,	/* Ґ - ӄ */
+	0x0561,	0x0587,	/* ա - և */
+	0x05d0,	0x05ea,	/* א - ת */
+	0x05f0,	0x05f2,	/* װ - ײ */
+	0x0621,	0x063a,	/* ء - غ */
+	0x0640,	0x064a,	/* ـ - ي */
+	0x0671,	0x06b7,	/* ٱ - ڷ */
+	0x06ba,	0x06be,	/* ں - ھ */
+	0x06c0,	0x06ce,	/* ۀ - ێ */
+	0x06d0,	0x06d3,	/* ې - ۓ */
+	0x0905,	0x0939,	/* अ - ह */
+	0x0958,	0x0961,	/* क़ - ॡ */
+	0x0985,	0x098c,	/* অ - ঌ */
+	0x098f,	0x0990,	/* এ - ঐ */
+	0x0993,	0x09a8,	/* ও - ন */
+	0x09aa,	0x09b0,	/* প - র */
+	0x09b6,	0x09b9,	/* শ - হ */
+	0x09dc,	0x09dd,	/* ড় - ঢ় */
+	0x09df,	0x09e1,	/* য় - ৡ */
+	0x09f0,	0x09f1,	/* ৰ - ৱ */
+	0x0a05,	0x0a0a,	/* ਅ - ਊ */
+	0x0a0f,	0x0a10,	/* ਏ - ਐ */
+	0x0a13,	0x0a28,	/* ਓ - ਨ */
+	0x0a2a,	0x0a30,	/* ਪ - ਰ */
+	0x0a32,	0x0a33,	/* ਲ - ਲ਼ */
+	0x0a35,	0x0a36,	/* ਵ - ਸ਼ */
+	0x0a38,	0x0a39,	/* ਸ - ਹ */
+	0x0a59,	0x0a5c,	/* ਖ਼ - ੜ */
+	0x0a85,	0x0a8b,	/* અ - ઋ */
+	0x0a8f,	0x0a91,	/* એ - ઑ */
+	0x0a93,	0x0aa8,	/* ઓ - ન */
+	0x0aaa,	0x0ab0,	/* પ - ર */
+	0x0ab2,	0x0ab3,	/* લ - ળ */
+	0x0ab5,	0x0ab9,	/* વ - હ */
+	0x0b05,	0x0b0c,	/* ଅ - ଌ */
+	0x0b0f,	0x0b10,	/* ଏ - ଐ */
+	0x0b13,	0x0b28,	/* ଓ - ନ */
+	0x0b2a,	0x0b30,	/* ପ - ର */
+	0x0b32,	0x0b33,	/* ଲ - ଳ */
+	0x0b36,	0x0b39,	/* ଶ - ହ */
+	0x0b5c,	0x0b5d,	/* ଡ଼ - ଢ଼ */
+	0x0b5f,	0x0b61,	/* ୟ - ୡ */
+	0x0b85,	0x0b8a,	/* அ - ஊ */
+	0x0b8e,	0x0b90,	/* எ - ஐ */
+	0x0b92,	0x0b95,	/* ஒ - க */
+	0x0b99,	0x0b9a,	/* ங - ச */
+	0x0b9e,	0x0b9f,	/* ஞ - ட */
+	0x0ba3,	0x0ba4,	/* ண - த */
+	0x0ba8,	0x0baa,	/* ந - ப */
+	0x0bae,	0x0bb5,	/* ம - வ */
+	0x0bb7,	0x0bb9,	/* ஷ - ஹ */
+	0x0c05,	0x0c0c,	/* అ - ఌ */
+	0x0c0e,	0x0c10,	/* ఎ - ఐ */
+	0x0c12,	0x0c28,	/* ఒ - న */
+	0x0c2a,	0x0c33,	/* ప - ళ */
+	0x0c35,	0x0c39,	/* వ - హ */
+	0x0c60,	0x0c61,	/* ౠ - ౡ */
+	0x0c85,	0x0c8c,	/* ಅ - ಌ */
+	0x0c8e,	0x0c90,	/* ಎ - ಐ */
+	0x0c92,	0x0ca8,	/* ಒ - ನ */
+	0x0caa,	0x0cb3,	/* ಪ - ಳ */
+	0x0cb5,	0x0cb9,	/* ವ - ಹ */
+	0x0ce0,	0x0ce1,	/* ೠ - ೡ */
+	0x0d05,	0x0d0c,	/* അ - ഌ */
+	0x0d0e,	0x0d10,	/* എ - ഐ */
+	0x0d12,	0x0d28,	/* ഒ - ന */
+	0x0d2a,	0x0d39,	/* പ - ഹ */
+	0x0d60,	0x0d61,	/* ൠ - ൡ */
+	0x0e01,	0x0e30,	/* ก - ะ */
+	0x0e32,	0x0e33,	/* า - ำ */
+	0x0e40,	0x0e46,	/* เ - ๆ */
+	0x0e5a,	0x0e5b,	/* ๚ - ๛ */
+	0x0e81,	0x0e82,	/* ກ - ຂ */
+	0x0e87,	0x0e88,	/* ງ - ຈ */
+	0x0e94,	0x0e97,	/* ດ - ທ */
+	0x0e99,	0x0e9f,	/* ນ - ຟ */
+	0x0ea1,	0x0ea3,	/* ມ - ຣ */
+	0x0eaa,	0x0eab,	/* ສ - ຫ */
+	0x0ead,	0x0eae,	/* ອ - ຮ */
+	0x0eb2,	0x0eb3,	/* າ - ຳ */
+	0x0ec0,	0x0ec4,	/* ເ - ໄ */
+	0x0edc,	0x0edd,	/* ໜ - ໝ */
+	0x0f18,	0x0f19,	/* ༘ - ༙ */
+	0x0f40,	0x0f47,	/* ཀ - ཇ */
+	0x0f49,	0x0f69,	/* ཉ - ཀྵ */
+	0x10d0,	0x10f6,	/* ა - ჶ */
+	0x1100,	0x1159,	/* ᄀ - ᅙ */
+	0x115f,	0x11a2,	/* ᅟ - ᆢ */
+	0x11a8,	0x11f9,	/* ᆨ - ᇹ */
+	0x1e00,	0x1e9b,	/* Ḁ - ẛ */
+	0x1f50,	0x1f57,	/* ὐ - ὗ */
+	0x1f80,	0x1fb4,	/* ᾀ - ᾴ */
+	0x1fb6,	0x1fbc,	/* ᾶ - ᾼ */
+	0x1fc2,	0x1fc4,	/* ῂ - ῄ */
+	0x1fc6,	0x1fcc,	/* ῆ - ῌ */
+	0x1fd0,	0x1fd3,	/* ῐ - ΐ */
+	0x1fd6,	0x1fdb,	/* ῖ - Ί */
+	0x1fe0,	0x1fec,	/* ῠ - Ῥ */
+	0x1ff2,	0x1ff4,	/* ῲ - ῴ */
+	0x1ff6,	0x1ffc,	/* ῶ - ῼ */
+	0x210a,	0x2113,	/* ℊ - ℓ */
+	0x2115,	0x211d,	/* ℕ - ℝ */
+	0x2120,	0x2122,	/* ℠ - ™ */
+	0x212a,	0x2131,	/* K - ℱ */
+	0x2133,	0x2138,	/* ℳ - ℸ */
+	0x3041,	0x3094,	/* ぁ - ゔ */
+	0x30a1,	0x30fa,	/* ァ - ヺ */
+	0x3105,	0x312c,	/* ㄅ - ㄬ */
+	0x3131,	0x318e,	/* ㄱ - ㆎ */
+	0x3192,	0x319f,	/* ㆒ - ㆟ */
+	0x3260,	0x327b,	/* ㉠ - ㉻ */
+	0x328a,	0x32b0,	/* ㊊ - ㊰ */
+	0x32d0,	0x32fe,	/* ㋐ - ㋾ */
+	0x3300,	0x3357,	/* ㌀ - ㍗ */
+	0x3371,	0x3376,	/* ㍱ - ㍶ */
+	0x337b,	0x3394,	/* ㍻ - ㎔ */
+	0x3399,	0x339e,	/* ㎙ - ㎞ */
+	0x33a9,	0x33ad,	/* ㎩ - ㎭ */
+	0x33b0,	0x33c1,	/* ㎰ - ㏁ */
+	0x33c3,	0x33c5,	/* ㏃ - ㏅ */
+	0x33c7,	0x33d7,	/* ㏇ - ㏗ */
+	0x33d9,	0x33dd,	/* ㏙ - ㏝ */
+	0x4e00,	0x9fff,	/* 一 - 鿿 */
+	0xac00,	0xd7a3,	/* 가 - 힣 */
+	0xf900,	0xfb06,	/* 豈 - st */
+	0xfb13,	0xfb17,	/* ﬓ - ﬗ */
+	0xfb1f,	0xfb28,	/* ײַ - ﬨ */
+	0xfb2a,	0xfb36,	/* שׁ - זּ */
+	0xfb38,	0xfb3c,	/* טּ - לּ */
+	0xfb40,	0xfb41,	/* נּ - סּ */
+	0xfb43,	0xfb44,	/* ףּ - פּ */
+	0xfb46,	0xfbb1,	/* צּ - ﮱ */
+	0xfbd3,	0xfd3d,	/* ﯓ - ﴽ */
+	0xfd50,	0xfd8f,	/* ﵐ - ﶏ */
+	0xfd92,	0xfdc7,	/* ﶒ - ﷇ */
+	0xfdf0,	0xfdf9,	/* ﷰ - ﷹ */
+	0xfe70,	0xfe72,	/* ﹰ - ﹲ */
+	0xfe76,	0xfefc,	/* ﹶ - ﻼ */
+	0xff66,	0xff6f,	/* ヲ - ッ */
+	0xff71,	0xff9d,	/* ア - ン */
+	0xffa0,	0xffbe,	/* ᅠ - ᄒ */
+	0xffc2,	0xffc7,	/* ᅡ - ᅦ */
+	0xffca,	0xffcf,	/* ᅧ - ᅬ */
+	0xffd2,	0xffd7,	/* ᅭ - ᅲ */
+	0xffda,	0xffdc,	/* ᅳ - ᅵ */
+};
+
+/*
+ * alpha singlets -
+ *	only covers ranges not in lower||upper
+ */
+static
+Rune	__alpha1[] =
+{
+	0x00aa,	/* ª */
+	0x00b5,	/* µ */
+	0x00ba,	/* º */
+	0x03da,	/* Ϛ */
+	0x03dc,	/* Ϝ */
+	0x03de,	/* Ϟ */
+	0x03e0,	/* Ϡ */
+	0x06d5,	/* ە */
+	0x09b2,	/* ল */
+	0x0a5e,	/* ਫ਼ */
+	0x0a8d,	/* ઍ */
+	0x0ae0,	/* ૠ */
+	0x0b9c,	/* ஜ */
+	0x0cde,	/* ೞ */
+	0x0e4f,	/* ๏ */
+	0x0e84,	/* ຄ */
+	0x0e8a,	/* ຊ */
+	0x0e8d,	/* ຍ */
+	0x0ea5,	/* ລ */
+	0x0ea7,	/* ວ */
+	0x0eb0,	/* ະ */
+	0x0ebd,	/* ຽ */
+	0x1fbe,	/* ι */
+	0x207f,	/* ⁿ */
+	0x20a8,	/* ₨ */
+	0x2102,	/* ℂ */
+	0x2107,	/* ℇ */
+	0x2124,	/* ℤ */
+	0x2126,	/* Ω */
+	0x2128,	/* ℨ */
+	0xfb3e,	/* מּ */
+	0xfe74,	/* ﹴ */
+};
+
+/*
+ * space ranges
+ */
+static
+Rune	__space2[] =
+{
+	0x0009,	0x000a,	/* tab and newline */
+	0x0020,	0x0020,	/* space */
+	0x00a0,	0x00a0,	/*   */
+	0x2000,	0x200b,	/*   - ​ */
+	0x2028,	0x2029,	/* 
 - 
 */
+	0x3000,	0x3000,	/*   */
+	0xfeff,	0xfeff,	/*  */
+};
+
+/*
+ * lower case ranges
+ *	3rd col is conversion excess 500
+ */
+static
+Rune	__toupper2[] =
+{
+	0x0061,	0x007a, 468,	/* a-z A-Z */
+	0x00e0,	0x00f6, 468,	/* à-ö À-Ö */
+	0x00f8,	0x00fe, 468,	/* ø-þ Ø-Þ */
+	0x0256,	0x0257, 295,	/* ɖ-ɗ Ɖ-Ɗ */
+	0x0258,	0x0259, 298,	/* ɘ-ə Ǝ-Ə */
+	0x028a,	0x028b, 283,	/* ʊ-ʋ Ʊ-Ʋ */
+	0x03ad,	0x03af, 463,	/* έ-ί Έ-Ί */
+	0x03b1,	0x03c1, 468,	/* α-ρ Α-Ρ */
+	0x03c3,	0x03cb, 468,	/* σ-ϋ Σ-Ϋ */
+	0x03cd,	0x03ce, 437,	/* ύ-ώ Ύ-Ώ */
+	0x0430,	0x044f, 468,	/* а-я А-Я */
+	0x0451,	0x045c, 420,	/* ё-ќ Ё-Ќ */
+	0x045e,	0x045f, 420,	/* ў-џ Ў-Џ */
+	0x0561,	0x0586, 452,	/* ա-ֆ Ա-Ֆ */
+	0x1f00,	0x1f07, 508,	/* ἀ-ἇ Ἀ-Ἇ */
+	0x1f10,	0x1f15, 508,	/* ἐ-ἕ Ἐ-Ἕ */
+	0x1f20,	0x1f27, 508,	/* ἠ-ἧ Ἠ-Ἧ */
+	0x1f30,	0x1f37, 508,	/* ἰ-ἷ Ἰ-Ἷ */
+	0x1f40,	0x1f45, 508,	/* ὀ-ὅ Ὀ-Ὅ */
+	0x1f60,	0x1f67, 508,	/* ὠ-ὧ Ὠ-Ὧ */
+	0x1f70,	0x1f71, 574,	/* ὰ-ά Ὰ-Ά */
+	0x1f72,	0x1f75, 586,	/* ὲ-ή Ὲ-Ή */
+	0x1f76,	0x1f77, 600,	/* ὶ-ί Ὶ-Ί */
+	0x1f78,	0x1f79, 628,	/* ὸ-ό Ὸ-Ό */
+	0x1f7a,	0x1f7b, 612,	/* ὺ-ύ Ὺ-Ύ */
+	0x1f7c,	0x1f7d, 626,	/* ὼ-ώ Ὼ-Ώ */
+	0x1f80,	0x1f87, 508,	/* ᾀ-ᾇ ᾈ-ᾏ */
+	0x1f90,	0x1f97, 508,	/* ᾐ-ᾗ ᾘ-ᾟ */
+	0x1fa0,	0x1fa7, 508,	/* ᾠ-ᾧ ᾨ-ᾯ */
+	0x1fb0,	0x1fb1, 508,	/* ᾰ-ᾱ Ᾰ-Ᾱ */
+	0x1fd0,	0x1fd1, 508,	/* ῐ-ῑ Ῐ-Ῑ */
+	0x1fe0,	0x1fe1, 508,	/* ῠ-ῡ Ῠ-Ῡ */
+	0x2170,	0x217f, 484,	/* ⅰ-ⅿ Ⅰ-Ⅿ */
+	0x24d0,	0x24e9, 474,	/* ⓐ-ⓩ Ⓐ-Ⓩ */
+	0xff41,	0xff5a, 468,	/* a-z A-Z */
+};
+
+/*
+ * lower case singlets
+ *	2nd col is conversion excess 500
+ */
+static
+Rune	__toupper1[] =
+{
+	0x00ff, 621,	/* ÿ Ÿ */
+	0x0101, 499,	/* ā Ā */
+	0x0103, 499,	/* ă Ă */
+	0x0105, 499,	/* ą Ą */
+	0x0107, 499,	/* ć Ć */
+	0x0109, 499,	/* ĉ Ĉ */
+	0x010b, 499,	/* ċ Ċ */
+	0x010d, 499,	/* č Č */
+	0x010f, 499,	/* ď Ď */
+	0x0111, 499,	/* đ Đ */
+	0x0113, 499,	/* ē Ē */
+	0x0115, 499,	/* ĕ Ĕ */
+	0x0117, 499,	/* ė Ė */
+	0x0119, 499,	/* ę Ę */
+	0x011b, 499,	/* ě Ě */
+	0x011d, 499,	/* ĝ Ĝ */
+	0x011f, 499,	/* ğ Ğ */
+	0x0121, 499,	/* ġ Ġ */
+	0x0123, 499,	/* ģ Ģ */
+	0x0125, 499,	/* ĥ Ĥ */
+	0x0127, 499,	/* ħ Ħ */
+	0x0129, 499,	/* ĩ Ĩ */
+	0x012b, 499,	/* ī Ī */
+	0x012d, 499,	/* ĭ Ĭ */
+	0x012f, 499,	/* į Į */
+	0x0131, 268,	/* ı I */
+	0x0133, 499,	/* ij IJ */
+	0x0135, 499,	/* ĵ Ĵ */
+	0x0137, 499,	/* ķ Ķ */
+	0x013a, 499,	/* ĺ Ĺ */
+	0x013c, 499,	/* ļ Ļ */
+	0x013e, 499,	/* ľ Ľ */
+	0x0140, 499,	/* ŀ Ŀ */
+	0x0142, 499,	/* ł Ł */
+	0x0144, 499,	/* ń Ń */
+	0x0146, 499,	/* ņ Ņ */
+	0x0148, 499,	/* ň Ň */
+	0x014b, 499,	/* ŋ Ŋ */
+	0x014d, 499,	/* ō Ō */
+	0x014f, 499,	/* ŏ Ŏ */
+	0x0151, 499,	/* ő Ő */
+	0x0153, 499,	/* œ Œ */
+	0x0155, 499,	/* ŕ Ŕ */
+	0x0157, 499,	/* ŗ Ŗ */
+	0x0159, 499,	/* ř Ř */
+	0x015b, 499,	/* ś Ś */
+	0x015d, 499,	/* ŝ Ŝ */
+	0x015f, 499,	/* ş Ş */
+	0x0161, 499,	/* š Š */
+	0x0163, 499,	/* ţ Ţ */
+	0x0165, 499,	/* ť Ť */
+	0x0167, 499,	/* ŧ Ŧ */
+	0x0169, 499,	/* ũ Ũ */
+	0x016b, 499,	/* ū Ū */
+	0x016d, 499,	/* ŭ Ŭ */
+	0x016f, 499,	/* ů Ů */
+	0x0171, 499,	/* ű Ű */
+	0x0173, 499,	/* ų Ų */
+	0x0175, 499,	/* ŵ Ŵ */
+	0x0177, 499,	/* ŷ Ŷ */
+	0x017a, 499,	/* ź Ź */
+	0x017c, 499,	/* ż Ż */
+	0x017e, 499,	/* ž Ž */
+	0x017f, 200,	/* ſ S */
+	0x0183, 499,	/* ƃ Ƃ */
+	0x0185, 499,	/* ƅ Ƅ */
+	0x0188, 499,	/* ƈ Ƈ */
+	0x018c, 499,	/* ƌ Ƌ */
+	0x0192, 499,	/* ƒ Ƒ */
+	0x0199, 499,	/* ƙ Ƙ */
+	0x01a1, 499,	/* ơ Ơ */
+	0x01a3, 499,	/* ƣ Ƣ */
+	0x01a5, 499,	/* ƥ Ƥ */
+	0x01a8, 499,	/* ƨ Ƨ */
+	0x01ad, 499,	/* ƭ Ƭ */
+	0x01b0, 499,	/* ư Ư */
+	0x01b4, 499,	/* ƴ Ƴ */
+	0x01b6, 499,	/* ƶ Ƶ */
+	0x01b9, 499,	/* ƹ Ƹ */
+	0x01bd, 499,	/* ƽ Ƽ */
+	0x01c5, 499,	/* Dž DŽ */
+	0x01c6, 498,	/* dž DŽ */
+	0x01c8, 499,	/* Lj LJ */
+	0x01c9, 498,	/* lj LJ */
+	0x01cb, 499,	/* Nj NJ */
+	0x01cc, 498,	/* nj NJ */
+	0x01ce, 499,	/* ǎ Ǎ */
+	0x01d0, 499,	/* ǐ Ǐ */
+	0x01d2, 499,	/* ǒ Ǒ */
+	0x01d4, 499,	/* ǔ Ǔ */
+	0x01d6, 499,	/* ǖ Ǖ */
+	0x01d8, 499,	/* ǘ Ǘ */
+	0x01da, 499,	/* ǚ Ǚ */
+	0x01dc, 499,	/* ǜ Ǜ */
+	0x01df, 499,	/* ǟ Ǟ */
+	0x01e1, 499,	/* ǡ Ǡ */
+	0x01e3, 499,	/* ǣ Ǣ */
+	0x01e5, 499,	/* ǥ Ǥ */
+	0x01e7, 499,	/* ǧ Ǧ */
+	0x01e9, 499,	/* ǩ Ǩ */
+	0x01eb, 499,	/* ǫ Ǫ */
+	0x01ed, 499,	/* ǭ Ǭ */
+	0x01ef, 499,	/* ǯ Ǯ */
+	0x01f2, 499,	/* Dz DZ */
+	0x01f3, 498,	/* dz DZ */
+	0x01f5, 499,	/* ǵ Ǵ */
+	0x01fb, 499,	/* ǻ Ǻ */
+	0x01fd, 499,	/* ǽ Ǽ */
+	0x01ff, 499,	/* ǿ Ǿ */
+	0x0201, 499,	/* ȁ Ȁ */
+	0x0203, 499,	/* ȃ Ȃ */
+	0x0205, 499,	/* ȅ Ȅ */
+	0x0207, 499,	/* ȇ Ȇ */
+	0x0209, 499,	/* ȉ Ȉ */
+	0x020b, 499,	/* ȋ Ȋ */
+	0x020d, 499,	/* ȍ Ȍ */
+	0x020f, 499,	/* ȏ Ȏ */
+	0x0211, 499,	/* ȑ Ȑ */
+	0x0213, 499,	/* ȓ Ȓ */
+	0x0215, 499,	/* ȕ Ȕ */
+	0x0217, 499,	/* ȗ Ȗ */
+	0x0253, 290,	/* ɓ Ɓ */
+	0x0254, 294,	/* ɔ Ɔ */
+	0x025b, 297,	/* ɛ Ɛ */
+	0x0260, 295,	/* ɠ Ɠ */
+	0x0263, 293,	/* ɣ Ɣ */
+	0x0268, 291,	/* ɨ Ɨ */
+	0x0269, 289,	/* ɩ Ɩ */
+	0x026f, 289,	/* ɯ Ɯ */
+	0x0272, 287,	/* ɲ Ɲ */
+	0x0283, 282,	/* ʃ Ʃ */
+	0x0288, 282,	/* ʈ Ʈ */
+	0x0292, 281,	/* ʒ Ʒ */
+	0x03ac, 462,	/* ά Ά */
+	0x03cc, 436,	/* ό Ό */
+	0x03d0, 438,	/* ϐ Β */
+	0x03d1, 443,	/* ϑ Θ */
+	0x03d5, 453,	/* ϕ Φ */
+	0x03d6, 446,	/* ϖ Π */
+	0x03e3, 499,	/* ϣ Ϣ */
+	0x03e5, 499,	/* ϥ Ϥ */
+	0x03e7, 499,	/* ϧ Ϧ */
+	0x03e9, 499,	/* ϩ Ϩ */
+	0x03eb, 499,	/* ϫ Ϫ */
+	0x03ed, 499,	/* ϭ Ϭ */
+	0x03ef, 499,	/* ϯ Ϯ */
+	0x03f0, 414,	/* ϰ Κ */
+	0x03f1, 420,	/* ϱ Ρ */
+	0x0461, 499,	/* ѡ Ѡ */
+	0x0463, 499,	/* ѣ Ѣ */
+	0x0465, 499,	/* ѥ Ѥ */
+	0x0467, 499,	/* ѧ Ѧ */
+	0x0469, 499,	/* ѩ Ѩ */
+	0x046b, 499,	/* ѫ Ѫ */
+	0x046d, 499,	/* ѭ Ѭ */
+	0x046f, 499,	/* ѯ Ѯ */
+	0x0471, 499,	/* ѱ Ѱ */
+	0x0473, 499,	/* ѳ Ѳ */
+	0x0475, 499,	/* ѵ Ѵ */
+	0x0477, 499,	/* ѷ Ѷ */
+	0x0479, 499,	/* ѹ Ѹ */
+	0x047b, 499,	/* ѻ Ѻ */
+	0x047d, 499,	/* ѽ Ѽ */
+	0x047f, 499,	/* ѿ Ѿ */
+	0x0481, 499,	/* ҁ Ҁ */
+	0x0491, 499,	/* ґ Ґ */
+	0x0493, 499,	/* ғ Ғ */
+	0x0495, 499,	/* ҕ Ҕ */
+	0x0497, 499,	/* җ Җ */
+	0x0499, 499,	/* ҙ Ҙ */
+	0x049b, 499,	/* қ Қ */
+	0x049d, 499,	/* ҝ Ҝ */
+	0x049f, 499,	/* ҟ Ҟ */
+	0x04a1, 499,	/* ҡ Ҡ */
+	0x04a3, 499,	/* ң Ң */
+	0x04a5, 499,	/* ҥ Ҥ */
+	0x04a7, 499,	/* ҧ Ҧ */
+	0x04a9, 499,	/* ҩ Ҩ */
+	0x04ab, 499,	/* ҫ Ҫ */
+	0x04ad, 499,	/* ҭ Ҭ */
+	0x04af, 499,	/* ү Ү */
+	0x04b1, 499,	/* ұ Ұ */
+	0x04b3, 499,	/* ҳ Ҳ */
+	0x04b5, 499,	/* ҵ Ҵ */
+	0x04b7, 499,	/* ҷ Ҷ */
+	0x04b9, 499,	/* ҹ Ҹ */
+	0x04bb, 499,	/* һ Һ */
+	0x04bd, 499,	/* ҽ Ҽ */
+	0x04bf, 499,	/* ҿ Ҿ */
+	0x04c2, 499,	/* ӂ Ӂ */
+	0x04c4, 499,	/* ӄ Ӄ */
+	0x04c8, 499,	/* ӈ Ӈ */
+	0x04cc, 499,	/* ӌ Ӌ */
+	0x04d1, 499,	/* ӑ Ӑ */
+	0x04d3, 499,	/* ӓ Ӓ */
+	0x04d5, 499,	/* ӕ Ӕ */
+	0x04d7, 499,	/* ӗ Ӗ */
+	0x04d9, 499,	/* ә Ә */
+	0x04db, 499,	/* ӛ Ӛ */
+	0x04dd, 499,	/* ӝ Ӝ */
+	0x04df, 499,	/* ӟ Ӟ */
+	0x04e1, 499,	/* ӡ Ӡ */
+	0x04e3, 499,	/* ӣ Ӣ */
+	0x04e5, 499,	/* ӥ Ӥ */
+	0x04e7, 499,	/* ӧ Ӧ */
+	0x04e9, 499,	/* ө Ө */
+	0x04eb, 499,	/* ӫ Ӫ */
+	0x04ef, 499,	/* ӯ Ӯ */
+	0x04f1, 499,	/* ӱ Ӱ */
+	0x04f3, 499,	/* ӳ Ӳ */
+	0x04f5, 499,	/* ӵ Ӵ */
+	0x04f9, 499,	/* ӹ Ӹ */
+	0x1e01, 499,	/* ḁ Ḁ */
+	0x1e03, 499,	/* ḃ Ḃ */
+	0x1e05, 499,	/* ḅ Ḅ */
+	0x1e07, 499,	/* ḇ Ḇ */
+	0x1e09, 499,	/* ḉ Ḉ */
+	0x1e0b, 499,	/* ḋ Ḋ */
+	0x1e0d, 499,	/* ḍ Ḍ */
+	0x1e0f, 499,	/* ḏ Ḏ */
+	0x1e11, 499,	/* ḑ Ḑ */
+	0x1e13, 499,	/* ḓ Ḓ */
+	0x1e15, 499,	/* ḕ Ḕ */
+	0x1e17, 499,	/* ḗ Ḗ */
+	0x1e19, 499,	/* ḙ Ḙ */
+	0x1e1b, 499,	/* ḛ Ḛ */
+	0x1e1d, 499,	/* ḝ Ḝ */
+	0x1e1f, 499,	/* ḟ Ḟ */
+	0x1e21, 499,	/* ḡ Ḡ */
+	0x1e23, 499,	/* ḣ Ḣ */
+	0x1e25, 499,	/* ḥ Ḥ */
+	0x1e27, 499,	/* ḧ Ḧ */
+	0x1e29, 499,	/* ḩ Ḩ */
+	0x1e2b, 499,	/* ḫ Ḫ */
+	0x1e2d, 499,	/* ḭ Ḭ */
+	0x1e2f, 499,	/* ḯ Ḯ */
+	0x1e31, 499,	/* ḱ Ḱ */
+	0x1e33, 499,	/* ḳ Ḳ */
+	0x1e35, 499,	/* ḵ Ḵ */
+	0x1e37, 499,	/* ḷ Ḷ */
+	0x1e39, 499,	/* ḹ Ḹ */
+	0x1e3b, 499,	/* ḻ Ḻ */
+	0x1e3d, 499,	/* ḽ Ḽ */
+	0x1e3f, 499,	/* ḿ Ḿ */
+	0x1e41, 499,	/* ṁ Ṁ */
+	0x1e43, 499,	/* ṃ Ṃ */
+	0x1e45, 499,	/* ṅ Ṅ */
+	0x1e47, 499,	/* ṇ Ṇ */
+	0x1e49, 499,	/* ṉ Ṉ */
+	0x1e4b, 499,	/* ṋ Ṋ */
+	0x1e4d, 499,	/* ṍ Ṍ */
+	0x1e4f, 499,	/* ṏ Ṏ */
+	0x1e51, 499,	/* ṑ Ṑ */
+	0x1e53, 499,	/* ṓ Ṓ */
+	0x1e55, 499,	/* ṕ Ṕ */
+	0x1e57, 499,	/* ṗ Ṗ */
+	0x1e59, 499,	/* ṙ Ṙ */
+	0x1e5b, 499,	/* ṛ Ṛ */
+	0x1e5d, 499,	/* ṝ Ṝ */
+	0x1e5f, 499,	/* ṟ Ṟ */
+	0x1e61, 499,	/* ṡ Ṡ */
+	0x1e63, 499,	/* ṣ Ṣ */
+	0x1e65, 499,	/* ṥ Ṥ */
+	0x1e67, 499,	/* ṧ Ṧ */
+	0x1e69, 499,	/* ṩ Ṩ */
+	0x1e6b, 499,	/* ṫ Ṫ */
+	0x1e6d, 499,	/* ṭ Ṭ */
+	0x1e6f, 499,	/* ṯ Ṯ */
+	0x1e71, 499,	/* ṱ Ṱ */
+	0x1e73, 499,	/* ṳ Ṳ */
+	0x1e75, 499,	/* ṵ Ṵ */
+	0x1e77, 499,	/* ṷ Ṷ */
+	0x1e79, 499,	/* ṹ Ṹ */
+	0x1e7b, 499,	/* ṻ Ṻ */
+	0x1e7d, 499,	/* ṽ Ṽ */
+	0x1e7f, 499,	/* ṿ Ṿ */
+	0x1e81, 499,	/* ẁ Ẁ */
+	0x1e83, 499,	/* ẃ Ẃ */
+	0x1e85, 499,	/* ẅ Ẅ */
+	0x1e87, 499,	/* ẇ Ẇ */
+	0x1e89, 499,	/* ẉ Ẉ */
+	0x1e8b, 499,	/* ẋ Ẋ */
+	0x1e8d, 499,	/* ẍ Ẍ */
+	0x1e8f, 499,	/* ẏ Ẏ */
+	0x1e91, 499,	/* ẑ Ẑ */
+	0x1e93, 499,	/* ẓ Ẓ */
+	0x1e95, 499,	/* ẕ Ẕ */
+	0x1ea1, 499,	/* ạ Ạ */
+	0x1ea3, 499,	/* ả Ả */
+	0x1ea5, 499,	/* ấ Ấ */
+	0x1ea7, 499,	/* ầ Ầ */
+	0x1ea9, 499,	/* ẩ Ẩ */
+	0x1eab, 499,	/* ẫ Ẫ */
+	0x1ead, 499,	/* ậ Ậ */
+	0x1eaf, 499,	/* ắ Ắ */
+	0x1eb1, 499,	/* ằ Ằ */
+	0x1eb3, 499,	/* ẳ Ẳ */
+	0x1eb5, 499,	/* ẵ Ẵ */
+	0x1eb7, 499,	/* ặ Ặ */
+	0x1eb9, 499,	/* ẹ Ẹ */
+	0x1ebb, 499,	/* ẻ Ẻ */
+	0x1ebd, 499,	/* ẽ Ẽ */
+	0x1ebf, 499,	/* ế Ế */
+	0x1ec1, 499,	/* ề Ề */
+	0x1ec3, 499,	/* ể Ể */
+	0x1ec5, 499,	/* ễ Ễ */
+	0x1ec7, 499,	/* ệ Ệ */
+	0x1ec9, 499,	/* ỉ Ỉ */
+	0x1ecb, 499,	/* ị Ị */
+	0x1ecd, 499,	/* ọ Ọ */
+	0x1ecf, 499,	/* ỏ Ỏ */
+	0x1ed1, 499,	/* ố Ố */
+	0x1ed3, 499,	/* ồ Ồ */
+	0x1ed5, 499,	/* ổ Ổ */
+	0x1ed7, 499,	/* ỗ Ỗ */
+	0x1ed9, 499,	/* ộ Ộ */
+	0x1edb, 499,	/* ớ Ớ */
+	0x1edd, 499,	/* ờ Ờ */
+	0x1edf, 499,	/* ở Ở */
+	0x1ee1, 499,	/* ỡ Ỡ */
+	0x1ee3, 499,	/* ợ Ợ */
+	0x1ee5, 499,	/* ụ Ụ */
+	0x1ee7, 499,	/* ủ Ủ */
+	0x1ee9, 499,	/* ứ Ứ */
+	0x1eeb, 499,	/* ừ Ừ */
+	0x1eed, 499,	/* ử Ử */
+	0x1eef, 499,	/* ữ Ữ */
+	0x1ef1, 499,	/* ự Ự */
+	0x1ef3, 499,	/* ỳ Ỳ */
+	0x1ef5, 499,	/* ỵ Ỵ */
+	0x1ef7, 499,	/* ỷ Ỷ */
+	0x1ef9, 499,	/* ỹ Ỹ */
+	0x1f51, 508,	/* ὑ Ὑ */
+	0x1f53, 508,	/* ὓ Ὓ */
+	0x1f55, 508,	/* ὕ Ὕ */
+	0x1f57, 508,	/* ὗ Ὗ */
+	0x1fb3, 509,	/* ᾳ ᾼ */
+	0x1fc3, 509,	/* ῃ ῌ */
+	0x1fe5, 507,	/* ῥ Ῥ */
+	0x1ff3, 509,	/* ῳ ῼ */
+};
+
+/*
+ * upper case ranges
+ *	3rd col is conversion excess 500
+ */
+static
+Rune	__tolower2[] =
+{
+	0x0041,	0x005a, 532,	/* A-Z a-z */
+	0x00c0,	0x00d6, 532,	/* À-Ö à-ö */
+	0x00d8,	0x00de, 532,	/* Ø-Þ ø-þ */
+	0x0189,	0x018a, 705,	/* Ɖ-Ɗ ɖ-ɗ */
+	0x018e,	0x018f, 702,	/* Ǝ-Ə ɘ-ə */
+	0x01b1,	0x01b2, 717,	/* Ʊ-Ʋ ʊ-ʋ */
+	0x0388,	0x038a, 537,	/* Έ-Ί έ-ί */
+	0x038e,	0x038f, 563,	/* Ύ-Ώ ύ-ώ */
+	0x0391,	0x03a1, 532,	/* Α-Ρ α-ρ */
+	0x03a3,	0x03ab, 532,	/* Σ-Ϋ σ-ϋ */
+	0x0401,	0x040c, 580,	/* Ё-Ќ ё-ќ */
+	0x040e,	0x040f, 580,	/* Ў-Џ ў-џ */
+	0x0410,	0x042f, 532,	/* А-Я а-я */
+	0x0531,	0x0556, 548,	/* Ա-Ֆ ա-ֆ */
+	0x10a0,	0x10c5, 548,	/* Ⴀ-Ⴥ ა-ჵ */
+	0x1f08,	0x1f0f, 492,	/* Ἀ-Ἇ ἀ-ἇ */
+	0x1f18,	0x1f1d, 492,	/* Ἐ-Ἕ ἐ-ἕ */
+	0x1f28,	0x1f2f, 492,	/* Ἠ-Ἧ ἠ-ἧ */
+	0x1f38,	0x1f3f, 492,	/* Ἰ-Ἷ ἰ-ἷ */
+	0x1f48,	0x1f4d, 492,	/* Ὀ-Ὅ ὀ-ὅ */
+	0x1f68,	0x1f6f, 492,	/* Ὠ-Ὧ ὠ-ὧ */
+	0x1f88,	0x1f8f, 492,	/* ᾈ-ᾏ ᾀ-ᾇ */
+	0x1f98,	0x1f9f, 492,	/* ᾘ-ᾟ ᾐ-ᾗ */
+	0x1fa8,	0x1faf, 492,	/* ᾨ-ᾯ ᾠ-ᾧ */
+	0x1fb8,	0x1fb9, 492,	/* Ᾰ-Ᾱ ᾰ-ᾱ */
+	0x1fba,	0x1fbb, 426,	/* Ὰ-Ά ὰ-ά */
+	0x1fc8,	0x1fcb, 414,	/* Ὲ-Ή ὲ-ή */
+	0x1fd8,	0x1fd9, 492,	/* Ῐ-Ῑ ῐ-ῑ */
+	0x1fda,	0x1fdb, 400,	/* Ὶ-Ί ὶ-ί */
+	0x1fe8,	0x1fe9, 492,	/* Ῠ-Ῡ ῠ-ῡ */
+	0x1fea,	0x1feb, 388,	/* Ὺ-Ύ ὺ-ύ */
+	0x1ff8,	0x1ff9, 372,	/* Ὸ-Ό ὸ-ό */
+	0x1ffa,	0x1ffb, 374,	/* Ὼ-Ώ ὼ-ώ */
+	0x2160,	0x216f, 516,	/* Ⅰ-Ⅿ ⅰ-ⅿ */
+	0x24b6,	0x24cf, 526,	/* Ⓐ-Ⓩ ⓐ-ⓩ */
+	0xff21,	0xff3a, 532,	/* A-Z a-z */
+};
+
+/*
+ * upper case singlets
+ *	2nd col is conversion excess 500
+ */
+static
+Rune	__tolower1[] =
+{
+	0x0100, 501,	/* Ā ā */
+	0x0102, 501,	/* Ă ă */
+	0x0104, 501,	/* Ą ą */
+	0x0106, 501,	/* Ć ć */
+	0x0108, 501,	/* Ĉ ĉ */
+	0x010a, 501,	/* Ċ ċ */
+	0x010c, 501,	/* Č č */
+	0x010e, 501,	/* Ď ď */
+	0x0110, 501,	/* Đ đ */
+	0x0112, 501,	/* Ē ē */
+	0x0114, 501,	/* Ĕ ĕ */
+	0x0116, 501,	/* Ė ė */
+	0x0118, 501,	/* Ę ę */
+	0x011a, 501,	/* Ě ě */
+	0x011c, 501,	/* Ĝ ĝ */
+	0x011e, 501,	/* Ğ ğ */
+	0x0120, 501,	/* Ġ ġ */
+	0x0122, 501,	/* Ģ ģ */
+	0x0124, 501,	/* Ĥ ĥ */
+	0x0126, 501,	/* Ħ ħ */
+	0x0128, 501,	/* Ĩ ĩ */
+	0x012a, 501,	/* Ī ī */
+	0x012c, 501,	/* Ĭ ĭ */
+	0x012e, 501,	/* Į į */
+	0x0130, 301,	/* İ i */
+	0x0132, 501,	/* IJ ij */
+	0x0134, 501,	/* Ĵ ĵ */
+	0x0136, 501,	/* Ķ ķ */
+	0x0139, 501,	/* Ĺ ĺ */
+	0x013b, 501,	/* Ļ ļ */
+	0x013d, 501,	/* Ľ ľ */
+	0x013f, 501,	/* Ŀ ŀ */
+	0x0141, 501,	/* Ł ł */
+	0x0143, 501,	/* Ń ń */
+	0x0145, 501,	/* Ņ ņ */
+	0x0147, 501,	/* Ň ň */
+	0x014a, 501,	/* Ŋ ŋ */
+	0x014c, 501,	/* Ō ō */
+	0x014e, 501,	/* Ŏ ŏ */
+	0x0150, 501,	/* Ő ő */
+	0x0152, 501,	/* Œ œ */
+	0x0154, 501,	/* Ŕ ŕ */
+	0x0156, 501,	/* Ŗ ŗ */
+	0x0158, 501,	/* Ř ř */
+	0x015a, 501,	/* Ś ś */
+	0x015c, 501,	/* Ŝ ŝ */
+	0x015e, 501,	/* Ş ş */
+	0x0160, 501,	/* Š š */
+	0x0162, 501,	/* Ţ ţ */
+	0x0164, 501,	/* Ť ť */
+	0x0166, 501,	/* Ŧ ŧ */
+	0x0168, 501,	/* Ũ ũ */
+	0x016a, 501,	/* Ū ū */
+	0x016c, 501,	/* Ŭ ŭ */
+	0x016e, 501,	/* Ů ů */
+	0x0170, 501,	/* Ű ű */
+	0x0172, 501,	/* Ų ų */
+	0x0174, 501,	/* Ŵ ŵ */
+	0x0176, 501,	/* Ŷ ŷ */
+	0x0178, 379,	/* Ÿ ÿ */
+	0x0179, 501,	/* Ź ź */
+	0x017b, 501,	/* Ż ż */
+	0x017d, 501,	/* Ž ž */
+	0x0181, 710,	/* Ɓ ɓ */
+	0x0182, 501,	/* Ƃ ƃ */
+	0x0184, 501,	/* Ƅ ƅ */
+	0x0186, 706,	/* Ɔ ɔ */
+	0x0187, 501,	/* Ƈ ƈ */
+	0x018b, 501,	/* Ƌ ƌ */
+	0x0190, 703,	/* Ɛ ɛ */
+	0x0191, 501,	/* Ƒ ƒ */
+	0x0193, 705,	/* Ɠ ɠ */
+	0x0194, 707,	/* Ɣ ɣ */
+	0x0196, 711,	/* Ɩ ɩ */
+	0x0197, 709,	/* Ɨ ɨ */
+	0x0198, 501,	/* Ƙ ƙ */
+	0x019c, 711,	/* Ɯ ɯ */
+	0x019d, 713,	/* Ɲ ɲ */
+	0x01a0, 501,	/* Ơ ơ */
+	0x01a2, 501,	/* Ƣ ƣ */
+	0x01a4, 501,	/* Ƥ ƥ */
+	0x01a7, 501,	/* Ƨ ƨ */
+	0x01a9, 718,	/* Ʃ ʃ */
+	0x01ac, 501,	/* Ƭ ƭ */
+	0x01ae, 718,	/* Ʈ ʈ */
+	0x01af, 501,	/* Ư ư */
+	0x01b3, 501,	/* Ƴ ƴ */
+	0x01b5, 501,	/* Ƶ ƶ */
+	0x01b7, 719,	/* Ʒ ʒ */
+	0x01b8, 501,	/* Ƹ ƹ */
+	0x01bc, 501,	/* Ƽ ƽ */
+	0x01c4, 502,	/* DŽ dž */
+	0x01c5, 501,	/* Dž dž */
+	0x01c7, 502,	/* LJ lj */
+	0x01c8, 501,	/* Lj lj */
+	0x01ca, 502,	/* NJ nj */
+	0x01cb, 501,	/* Nj nj */
+	0x01cd, 501,	/* Ǎ ǎ */
+	0x01cf, 501,	/* Ǐ ǐ */
+	0x01d1, 501,	/* Ǒ ǒ */
+	0x01d3, 501,	/* Ǔ ǔ */
+	0x01d5, 501,	/* Ǖ ǖ */
+	0x01d7, 501,	/* Ǘ ǘ */
+	0x01d9, 501,	/* Ǚ ǚ */
+	0x01db, 501,	/* Ǜ ǜ */
+	0x01de, 501,	/* Ǟ ǟ */
+	0x01e0, 501,	/* Ǡ ǡ */
+	0x01e2, 501,	/* Ǣ ǣ */
+	0x01e4, 501,	/* Ǥ ǥ */
+	0x01e6, 501,	/* Ǧ ǧ */
+	0x01e8, 501,	/* Ǩ ǩ */
+	0x01ea, 501,	/* Ǫ ǫ */
+	0x01ec, 501,	/* Ǭ ǭ */
+	0x01ee, 501,	/* Ǯ ǯ */
+	0x01f1, 502,	/* DZ dz */
+	0x01f2, 501,	/* Dz dz */
+	0x01f4, 501,	/* Ǵ ǵ */
+	0x01fa, 501,	/* Ǻ ǻ */
+	0x01fc, 501,	/* Ǽ ǽ */
+	0x01fe, 501,	/* Ǿ ǿ */
+	0x0200, 501,	/* Ȁ ȁ */
+	0x0202, 501,	/* Ȃ ȃ */
+	0x0204, 501,	/* Ȅ ȅ */
+	0x0206, 501,	/* Ȇ ȇ */
+	0x0208, 501,	/* Ȉ ȉ */
+	0x020a, 501,	/* Ȋ ȋ */
+	0x020c, 501,	/* Ȍ ȍ */
+	0x020e, 501,	/* Ȏ ȏ */
+	0x0210, 501,	/* Ȑ ȑ */
+	0x0212, 501,	/* Ȓ ȓ */
+	0x0214, 501,	/* Ȕ ȕ */
+	0x0216, 501,	/* Ȗ ȗ */
+	0x0386, 538,	/* Ά ά */
+	0x038c, 564,	/* Ό ό */
+	0x03e2, 501,	/* Ϣ ϣ */
+	0x03e4, 501,	/* Ϥ ϥ */
+	0x03e6, 501,	/* Ϧ ϧ */
+	0x03e8, 501,	/* Ϩ ϩ */
+	0x03ea, 501,	/* Ϫ ϫ */
+	0x03ec, 501,	/* Ϭ ϭ */
+	0x03ee, 501,	/* Ϯ ϯ */
+	0x0460, 501,	/* Ѡ ѡ */
+	0x0462, 501,	/* Ѣ ѣ */
+	0x0464, 501,	/* Ѥ ѥ */
+	0x0466, 501,	/* Ѧ ѧ */
+	0x0468, 501,	/* Ѩ ѩ */
+	0x046a, 501,	/* Ѫ ѫ */
+	0x046c, 501,	/* Ѭ ѭ */
+	0x046e, 501,	/* Ѯ ѯ */
+	0x0470, 501,	/* Ѱ ѱ */
+	0x0472, 501,	/* Ѳ ѳ */
+	0x0474, 501,	/* Ѵ ѵ */
+	0x0476, 501,	/* Ѷ ѷ */
+	0x0478, 501,	/* Ѹ ѹ */
+	0x047a, 501,	/* Ѻ ѻ */
+	0x047c, 501,	/* Ѽ ѽ */
+	0x047e, 501,	/* Ѿ ѿ */
+	0x0480, 501,	/* Ҁ ҁ */
+	0x0490, 501,	/* Ґ ґ */
+	0x0492, 501,	/* Ғ ғ */
+	0x0494, 501,	/* Ҕ ҕ */
+	0x0496, 501,	/* Җ җ */
+	0x0498, 501,	/* Ҙ ҙ */
+	0x049a, 501,	/* Қ қ */
+	0x049c, 501,	/* Ҝ ҝ */
+	0x049e, 501,	/* Ҟ ҟ */
+	0x04a0, 501,	/* Ҡ ҡ */
+	0x04a2, 501,	/* Ң ң */
+	0x04a4, 501,	/* Ҥ ҥ */
+	0x04a6, 501,	/* Ҧ ҧ */
+	0x04a8, 501,	/* Ҩ ҩ */
+	0x04aa, 501,	/* Ҫ ҫ */
+	0x04ac, 501,	/* Ҭ ҭ */
+	0x04ae, 501,	/* Ү ү */
+	0x04b0, 501,	/* Ұ ұ */
+	0x04b2, 501,	/* Ҳ ҳ */
+	0x04b4, 501,	/* Ҵ ҵ */
+	0x04b6, 501,	/* Ҷ ҷ */
+	0x04b8, 501,	/* Ҹ ҹ */
+	0x04ba, 501,	/* Һ һ */
+	0x04bc, 501,	/* Ҽ ҽ */
+	0x04be, 501,	/* Ҿ ҿ */
+	0x04c1, 501,	/* Ӂ ӂ */
+	0x04c3, 501,	/* Ӄ ӄ */
+	0x04c7, 501,	/* Ӈ ӈ */
+	0x04cb, 501,	/* Ӌ ӌ */
+	0x04d0, 501,	/* Ӑ ӑ */
+	0x04d2, 501,	/* Ӓ ӓ */
+	0x04d4, 501,	/* Ӕ ӕ */
+	0x04d6, 501,	/* Ӗ ӗ */
+	0x04d8, 501,	/* Ә ә */
+	0x04da, 501,	/* Ӛ ӛ */
+	0x04dc, 501,	/* Ӝ ӝ */
+	0x04de, 501,	/* Ӟ ӟ */
+	0x04e0, 501,	/* Ӡ ӡ */
+	0x04e2, 501,	/* Ӣ ӣ */
+	0x04e4, 501,	/* Ӥ ӥ */
+	0x04e6, 501,	/* Ӧ ӧ */
+	0x04e8, 501,	/* Ө ө */
+	0x04ea, 501,	/* Ӫ ӫ */
+	0x04ee, 501,	/* Ӯ ӯ */
+	0x04f0, 501,	/* Ӱ ӱ */
+	0x04f2, 501,	/* Ӳ ӳ */
+	0x04f4, 501,	/* Ӵ ӵ */
+	0x04f8, 501,	/* Ӹ ӹ */
+	0x1e00, 501,	/* Ḁ ḁ */
+	0x1e02, 501,	/* Ḃ ḃ */
+	0x1e04, 501,	/* Ḅ ḅ */
+	0x1e06, 501,	/* Ḇ ḇ */
+	0x1e08, 501,	/* Ḉ ḉ */
+	0x1e0a, 501,	/* Ḋ ḋ */
+	0x1e0c, 501,	/* Ḍ ḍ */
+	0x1e0e, 501,	/* Ḏ ḏ */
+	0x1e10, 501,	/* Ḑ ḑ */
+	0x1e12, 501,	/* Ḓ ḓ */
+	0x1e14, 501,	/* Ḕ ḕ */
+	0x1e16, 501,	/* Ḗ ḗ */
+	0x1e18, 501,	/* Ḙ ḙ */
+	0x1e1a, 501,	/* Ḛ ḛ */
+	0x1e1c, 501,	/* Ḝ ḝ */
+	0x1e1e, 501,	/* Ḟ ḟ */
+	0x1e20, 501,	/* Ḡ ḡ */
+	0x1e22, 501,	/* Ḣ ḣ */
+	0x1e24, 501,	/* Ḥ ḥ */
+	0x1e26, 501,	/* Ḧ ḧ */
+	0x1e28, 501,	/* Ḩ ḩ */
+	0x1e2a, 501,	/* Ḫ ḫ */
+	0x1e2c, 501,	/* Ḭ ḭ */
+	0x1e2e, 501,	/* Ḯ ḯ */
+	0x1e30, 501,	/* Ḱ ḱ */
+	0x1e32, 501,	/* Ḳ ḳ */
+	0x1e34, 501,	/* Ḵ ḵ */
+	0x1e36, 501,	/* Ḷ ḷ */
+	0x1e38, 501,	/* Ḹ ḹ */
+	0x1e3a, 501,	/* Ḻ ḻ */
+	0x1e3c, 501,	/* Ḽ ḽ */
+	0x1e3e, 501,	/* Ḿ ḿ */
+	0x1e40, 501,	/* Ṁ ṁ */
+	0x1e42, 501,	/* Ṃ ṃ */
+	0x1e44, 501,	/* Ṅ ṅ */
+	0x1e46, 501,	/* Ṇ ṇ */
+	0x1e48, 501,	/* Ṉ ṉ */
+	0x1e4a, 501,	/* Ṋ ṋ */
+	0x1e4c, 501,	/* Ṍ ṍ */
+	0x1e4e, 501,	/* Ṏ ṏ */
+	0x1e50, 501,	/* Ṑ ṑ */
+	0x1e52, 501,	/* Ṓ ṓ */
+	0x1e54, 501,	/* Ṕ ṕ */
+	0x1e56, 501,	/* Ṗ ṗ */
+	0x1e58, 501,	/* Ṙ ṙ */
+	0x1e5a, 501,	/* Ṛ ṛ */
+	0x1e5c, 501,	/* Ṝ ṝ */
+	0x1e5e, 501,	/* Ṟ ṟ */
+	0x1e60, 501,	/* Ṡ ṡ */
+	0x1e62, 501,	/* Ṣ ṣ */
+	0x1e64, 501,	/* Ṥ ṥ */
+	0x1e66, 501,	/* Ṧ ṧ */
+	0x1e68, 501,	/* Ṩ ṩ */
+	0x1e6a, 501,	/* Ṫ ṫ */
+	0x1e6c, 501,	/* Ṭ ṭ */
+	0x1e6e, 501,	/* Ṯ ṯ */
+	0x1e70, 501,	/* Ṱ ṱ */
+	0x1e72, 501,	/* Ṳ ṳ */
+	0x1e74, 501,	/* Ṵ ṵ */
+	0x1e76, 501,	/* Ṷ ṷ */
+	0x1e78, 501,	/* Ṹ ṹ */
+	0x1e7a, 501,	/* Ṻ ṻ */
+	0x1e7c, 501,	/* Ṽ ṽ */
+	0x1e7e, 501,	/* Ṿ ṿ */
+	0x1e80, 501,	/* Ẁ ẁ */
+	0x1e82, 501,	/* Ẃ ẃ */
+	0x1e84, 501,	/* Ẅ ẅ */
+	0x1e86, 501,	/* Ẇ ẇ */
+	0x1e88, 501,	/* Ẉ ẉ */
+	0x1e8a, 501,	/* Ẋ ẋ */
+	0x1e8c, 501,	/* Ẍ ẍ */
+	0x1e8e, 501,	/* Ẏ ẏ */
+	0x1e90, 501,	/* Ẑ ẑ */
+	0x1e92, 501,	/* Ẓ ẓ */
+	0x1e94, 501,	/* Ẕ ẕ */
+	0x1ea0, 501,	/* Ạ ạ */
+	0x1ea2, 501,	/* Ả ả */
+	0x1ea4, 501,	/* Ấ ấ */
+	0x1ea6, 501,	/* Ầ ầ */
+	0x1ea8, 501,	/* Ẩ ẩ */
+	0x1eaa, 501,	/* Ẫ ẫ */
+	0x1eac, 501,	/* Ậ ậ */
+	0x1eae, 501,	/* Ắ ắ */
+	0x1eb0, 501,	/* Ằ ằ */
+	0x1eb2, 501,	/* Ẳ ẳ */
+	0x1eb4, 501,	/* Ẵ ẵ */
+	0x1eb6, 501,	/* Ặ ặ */
+	0x1eb8, 501,	/* Ẹ ẹ */
+	0x1eba, 501,	/* Ẻ ẻ */
+	0x1ebc, 501,	/* Ẽ ẽ */
+	0x1ebe, 501,	/* Ế ế */
+	0x1ec0, 501,	/* Ề ề */
+	0x1ec2, 501,	/* Ể ể */
+	0x1ec4, 501,	/* Ễ ễ */
+	0x1ec6, 501,	/* Ệ ệ */
+	0x1ec8, 501,	/* Ỉ ỉ */
+	0x1eca, 501,	/* Ị ị */
+	0x1ecc, 501,	/* Ọ ọ */
+	0x1ece, 501,	/* Ỏ ỏ */
+	0x1ed0, 501,	/* Ố ố */
+	0x1ed2, 501,	/* Ồ ồ */
+	0x1ed4, 501,	/* Ổ ổ */
+	0x1ed6, 501,	/* Ỗ ỗ */
+	0x1ed8, 501,	/* Ộ ộ */
+	0x1eda, 501,	/* Ớ ớ */
+	0x1edc, 501,	/* Ờ ờ */
+	0x1ede, 501,	/* Ở ở */
+	0x1ee0, 501,	/* Ỡ ỡ */
+	0x1ee2, 501,	/* Ợ ợ */
+	0x1ee4, 501,	/* Ụ ụ */
+	0x1ee6, 501,	/* Ủ ủ */
+	0x1ee8, 501,	/* Ứ ứ */
+	0x1eea, 501,	/* Ừ ừ */
+	0x1eec, 501,	/* Ử ử */
+	0x1eee, 501,	/* Ữ ữ */
+	0x1ef0, 501,	/* Ự ự */
+	0x1ef2, 501,	/* Ỳ ỳ */
+	0x1ef4, 501,	/* Ỵ ỵ */
+	0x1ef6, 501,	/* Ỷ ỷ */
+	0x1ef8, 501,	/* Ỹ ỹ */
+	0x1f59, 492,	/* Ὑ ὑ */
+	0x1f5b, 492,	/* Ὓ ὓ */
+	0x1f5d, 492,	/* Ὕ ὕ */
+	0x1f5f, 492,	/* Ὗ ὗ */
+	0x1fbc, 491,	/* ᾼ ᾳ */
+	0x1fcc, 491,	/* ῌ ῃ */
+	0x1fec, 493,	/* Ῥ ῥ */
+	0x1ffc, 491,	/* ῼ ῳ */
+};
+
+/*
+ * title characters are those between
+ * upper and lower case. ie DZ Dz dz
+ */
+static
+Rune	__totitle1[] =
+{
+	0x01c4, 501,	/* DŽ Dž */
+	0x01c6, 499,	/* dž Dž */
+	0x01c7, 501,	/* LJ Lj */
+	0x01c9, 499,	/* lj Lj */
+	0x01ca, 501,	/* NJ Nj */
+	0x01cc, 499,	/* nj Nj */
+	0x01f1, 501,	/* DZ Dz */
+	0x01f3, 499,	/* dz Dz */
+};
+
+static
+Rune*
+bsearch(Rune c, Rune *t, int n, int ne)
+{
+	Rune *p;
+	int m;
+
+	while(n > 1) {
+		m = n/2;
+		p = t + m*ne;
+		if(c >= p[0]) {
+			t = p;
+			n = n-m;
+		} else
+			n = m;
+	}
+	if(n && c >= t[0])
+		return t;
+	return 0;
+}
+
+Rune
+tolowerrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 500;
+	p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 500;
+	return c;
+}
+
+Rune
+toupperrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 500;
+	p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 500;
+	return c;
+}
+
+Rune
+totitlerune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __totitle1, nelem(__totitle1)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 500;
+	return c;
+}
+
+int
+islowerrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+int
+isupperrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+int
+isalpharune(Rune c)
+{
+	Rune *p;
+
+	if(isupperrune(c) || islowerrune(c))
+		return 1;
+	p = bsearch(c, __alpha2, nelem(__alpha2)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = bsearch(c, __alpha1, nelem(__alpha1), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+int
+istitlerune(Rune c)
+{
+	return isupperrune(c) && islowerrune(c);
+}
+
+int
+isspacerune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __space2, nelem(__space2)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}

+ 14 - 0
sys/src/ape/lib/utf/utfdef.h

@@ -0,0 +1,14 @@
+#define uchar _utfuchar
+#define ushort _utfushort
+#define uint _utfuint
+#define ulong _utfulong
+#define vlong _utfvlong
+#define uvlong _utfuvlong
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)

+ 51 - 0
sys/src/ape/lib/utf/utfecpy.c

@@ -0,0 +1,51 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+static void*
+memccpy(void *a1, void *a2, int c, ulong n)
+{
+	uchar *s1, *s2;
+
+	s1 = a1;
+	s2 = a2;
+	c &= 0xFF;
+	while(n > 0) {
+		if((*s1++ = *s2++) == c)
+			return s1;
+		n--;
+	}
+	return 0;
+}
+char*
+utfecpy(char *to, char *e, char *from)
+{
+	char *end;
+
+	if(to >= e)
+		return to;
+	end = memccpy(to, from, '\0', e - to);
+	if(end == nil){
+		end = e-1;
+		while(end>to && (*--end&0xC0)==0x80)
+			;
+		*end = '\0';
+	}else{
+		end--;
+	}
+	return end;
+}

+ 38 - 0
sys/src/ape/lib/utf/utflen.c

@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utflen(char *s)
+{
+	int c;
+	long n;
+	Rune rune;
+
+	n = 0;
+	for(;;) {
+		c = *(uchar*)s;
+		if(c < Runeself) {
+			if(c == 0)
+				return n;
+			s++;
+		} else
+			s += chartorune(&rune, s);
+		n++;
+	}
+	return 0;
+}

+ 41 - 0
sys/src/ape/lib/utf/utfnlen.c

@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utfnlen(char *s, long m)
+{
+	int c;
+	long n;
+	Rune rune;
+	char *es;
+
+	es = s + m;
+	for(n = 0; s < es; n++) {
+		c = *(uchar*)s;
+		if(c < Runeself){
+			if(c == '\0')
+				break;
+			s++;
+			continue;
+		}
+		if(!fullrune(s, es-s))
+			break;
+		s += chartorune(&rune, s);
+	}
+	return n;
+}

+ 46 - 0
sys/src/ape/lib/utf/utfrrune.c

@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+char*
+utfrrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	char *s1;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strrchr(s, c);
+
+	s1 = 0;
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return s1;
+			if(c1 == c)
+				s1 = s;
+			s++;
+			continue;
+		}
+		c1 = chartorune(&r, s);
+		if(r == c)
+			s1 = s;
+		s += c1;
+	}
+	return 0;
+}

+ 45 - 0
sys/src/ape/lib/utf/utfrune.c

@@ -0,0 +1,45 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+char*
+utfrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	int n;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strchr(s, c);
+
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return 0;
+			if(c1 == c)
+				return s;
+			s++;
+			continue;
+		}
+		n = chartorune(&r, s);
+		if(r == c)
+			return s;
+		s += n;
+	}
+	return 0;
+}

+ 41 - 0
sys/src/ape/lib/utf/utfutf.c

@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+utfutf(char *s1, char *s2)
+{
+	char *p;
+	long f, n1, n2;
+	Rune r;
+
+	n1 = chartorune(&r, s2);
+	f = r;
+	if(f <= Runesync)		/* represents self */
+		return strstr(s1, s2);
+
+	n2 = strlen(s2);
+	for(p=s1; p=utfrune(p, f); p+=n1)
+		if(strncmp(p, s2, n2) == 0)
+			return p;
+	return 0;
+}

+ 1 - 1
sys/src/cmd/disk/mkext.c

@@ -151,7 +151,7 @@ mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
 		rerrstr(olderr, sizeof(olderr));
 		rerrstr(olderr, sizeof(olderr));
 		if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
 		if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
 			free(d);
 			free(d);
-			warn("can't make directory %q, mode %luo: %s", name, olderr);
+			warn("can't make directory %q, mode %luo: %s", name, mode, olderr);
 			return;
 			return;
 		}
 		}
 	}
 	}

+ 2 - 2
sys/src/cmd/hget.c

@@ -779,8 +779,8 @@ doftp(URL *u, URL *px, Range *r, int out, long mtime)
 	char conndir[NETPATHLEN];
 	char conndir[NETPATHLEN];
 	char *p;
 	char *p;
 
 
-	/* untestet, proxy dosn't work with ftp (I think) */
-	if(px->host != nil){
+	/* untested, proxy dosn't work with ftp (I think) */
+	if(px->host == nil){
 		ctl = dial(netmkaddr(u->host, tcpdir, u->port), 0, conndir, 0);
 		ctl = dial(netmkaddr(u->host, tcpdir, u->port), 0, conndir, 0);
 	} else {
 	} else {
 		ctl = dial(netmkaddr(px->host, tcpdir, px->port), 0, conndir, 0);
 		ctl = dial(netmkaddr(px->host, tcpdir, px->port), 0, conndir, 0);

+ 1 - 1
sys/src/cmd/ip/httpd/webls.c

@@ -108,7 +108,7 @@ allowed(char *dir)
 	int	okay;
 	int	okay;
 	Resub	match;
 	Resub	match;
 
 
-	if (strstr(dir, ".."))
+	if (strcmp(dir, "..") == 0 || strncmp(dir, "../", 3) == 0)
 		return(0);
 		return(0);
 	if (aio == nil)
 	if (aio == nil)
 		return(0);
 		return(0);

+ 2 - 2
sys/src/cmd/ratfs/misc.c

@@ -2,8 +2,8 @@
 #include <ip.h>
 #include <ip.h>
 
 
 enum {
 enum {
-	Maxdoms	=	10,	/* max domains in a path */
-	Timeout =	15*60,	/* seconds until temporarily trusted addr times out */
+	Maxdoms	=	10,		/* max domains in a path */
+	Timeout =	2*60*60,	/* seconds until temporarily trusted addr times out */
 };
 };
 
 
 static	int	accountmatch(char*, char**, int, char*);
 static	int	accountmatch(char*, char**, int, char*);

+ 198 - 56
sys/src/cmd/tar.c

@@ -8,6 +8,30 @@
 #define NBLOCK	40	/* maximum blocksize */
 #define NBLOCK	40	/* maximum blocksize */
 #define DBLOCK	20	/* default blocksize */
 #define DBLOCK	20	/* default blocksize */
 #define NAMSIZ	100
 #define NAMSIZ	100
+
+enum {
+	Maxpfx = 155,		/* from POSIX */
+	Maxname = NAMSIZ + 1 + Maxpfx,
+};
+
+/* POSIX link flags */
+enum {
+	LF_PLAIN1 =	'\0',
+	LF_PLAIN2 =	'0',
+	LF_LINK =	'1',
+	LF_SYMLINK1 =	'2',
+	LF_SYMLINK2 =	's',
+	LF_CHR =	'3',
+	LF_BLK =	'4',
+	LF_DIR =	'5',
+	LF_FIFO =	'6',
+	LF_CONTIG =	'7',
+	/* 'A' - 'Z' are reserved for custom implementations */
+};
+
+#define islink(lf)	(isreallink(lf) || issymlink(lf))
+#define isreallink(lf)	((lf) == LF_LINK)
+#define issymlink(lf)	((lf) == LF_SYMLINK1 || (lf) == LF_SYMLINK2)
 union	hblock
 union	hblock
 {
 {
 	char	dummy[TBLOCK];
 	char	dummy[TBLOCK];
@@ -22,14 +46,25 @@ union	hblock
 		char	chksum[8];
 		char	chksum[8];
 		char	linkflag;
 		char	linkflag;
 		char	linkname[NAMSIZ];
 		char	linkname[NAMSIZ];
+		/* rest are defined by POSIX's ustar format; see p1003.2b */
+		char	magic[6];	/* "ustar" */
+		char	version[2];
+		char	uname[32];
+		char	gname[32];
+		char	devmajor[8];
+		char	devminor[8];
+		char	prefix[155];  /* if non-null, path = prefix "/" name */
 	} dbuf;
 	} dbuf;
 } dblock, tbuf[NBLOCK];
 } dblock, tbuf[NBLOCK];
 
 
 Dir *stbuf;
 Dir *stbuf;
 Biobuf bout;
 Biobuf bout;
+static int ustar;		/* flag: tape block just read is ustar format */
+static char *fullname;			/* if non-nil, prefix "/" name */
 
 
 int	rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag, Rflag;
 int	rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag, Rflag;
 int	uflag, gflag;
 int	uflag, gflag;
+static int posix;		/* flag: we're writing ustar format archive */
 int	chksum, recno, first;
 int	chksum, recno, first;
 int	nblock = DBLOCK;
 int	nblock = DBLOCK;
 
 
@@ -54,6 +89,109 @@ void	backtar(void);
 void	flushtar(void);
 void	flushtar(void);
 void	affix(int, char *);
 void	affix(int, char *);
 int	volprompt(void);
 int	volprompt(void);
+
+static int
+isustar(struct header *hp)
+{
+	return strcmp(hp->magic, "ustar") == 0;
+}
+
+static void
+setustar(struct header *hp)
+{
+	strncpy(hp->magic, "ustar", sizeof hp->magic);
+	strncpy(hp->version, "00", sizeof hp->version);
+}
+
+/*
+ * s is at most n bytes long, but need not be NUL-terminated.
+ * if shorter than n bytes, all bytes after the first NUL must also
+ * be NUL.
+ */
+static int
+strnlen(char *s, int n)
+{
+	if (s[n - 1] != '\0')
+		return n;
+	else
+		return strlen(s);
+}
+
+/* set fullname from header; called from getdir() */
+static void
+getfullname(struct header *hp)
+{
+	int pfxlen, namlen;
+
+	if (fullname != nil)
+		free(fullname);
+	namlen = strnlen(hp->name, sizeof hp->name);
+	if (hp->prefix[0] == '\0' || !ustar) {
+		fullname = malloc(namlen + 1);
+		if (fullname == nil)
+			sysfatal("out of memory: %r");
+		memmove(fullname, hp->name, namlen);
+		fullname[namlen] = '\0';
+		return;
+	}
+	pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
+	fullname = malloc(pfxlen + 1 + namlen + 1);
+	if (fullname == nil)
+		sysfatal("out of memory: %r");
+	memmove(fullname, hp->prefix, pfxlen);
+	fullname[pfxlen] = '/';
+	memmove(fullname + pfxlen + 1, hp->name, namlen);
+	fullname[pfxlen + 1 + namlen] = '\0';
+}
+
+/*
+ * if name is longer than NAMSIZ bytes, try to split it at a slash and fit the
+ * pieces into hp->prefix and hp->name.
+ */
+static int
+putfullname(struct header *hp, char *name)
+{
+	int namlen, pfxlen;
+	char *sl, *osl;
+
+	namlen = strlen(name);
+	if (namlen <= NAMSIZ) {
+		strncpy(hp->name, name, NAMSIZ);
+		hp->prefix[0] = '\0';		/* ustar paranoia */
+		return 0;
+	}
+	if (!posix || namlen > NAMSIZ + 1 + sizeof hp->prefix) {
+		fprint(2, "tar: name too long for tar header: %s\n", name);
+		return -1;
+	}
+	/*
+	 * try various splits until one results in pieces that fit into the
+	 * appropriate fields of the header.  look for slashes from right
+	 * to left, in the hopes of putting the largest part of the name into
+	 * hp->prefix, which is larger than hp->name.
+	 */
+	sl = strrchr(name, '/');
+	while (sl != nil) {
+		pfxlen = sl - name;
+		if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= NAMSIZ)
+			break;
+		osl = sl;
+		*osl = '\0';
+		sl = strrchr(name, '/');
+		*osl = '/';
+	}
+	if (sl == nil) {
+		fprint(2, "tar: name can't be split to fit tar header: %s\n",
+			name);
+		return -1;
+	}
+	*sl = '\0';
+	strncpy(hp->prefix, name, sizeof hp->prefix);
+	*sl = '/';
+	strncpy(hp->name, sl + 1, sizeof hp->name);
+	return 0;
+}
+
 void
 void
 main(int argc, char **argv)
 main(int argc, char **argv)
 {
 {
@@ -91,6 +229,9 @@ main(int argc, char **argv)
 			cflag++;
 			cflag++;
 			rflag++;
 			rflag++;
 			break;
 			break;
+		case 'p':
+			posix++;
+			break;
 		case 'r':
 		case 'r':
 			rflag++;
 			rflag++;
 			break;
 			break;
@@ -248,10 +389,8 @@ getdir(void)
 		return;
 		return;
 	if(stbuf == nil){
 	if(stbuf == nil){
 		stbuf = malloc(sizeof(Dir));
 		stbuf = malloc(sizeof(Dir));
-		if(stbuf == nil) {
-			fprint(2, "tar: can't malloc: %r\n");
-			exits("malloc");
-		}
+		if(stbuf == nil)
+			sysfatal("out of memory: %r");
 	}
 	}
 	sp = stbuf;
 	sp = stbuf;
 	sp->mode = strtol(dblock.dbuf.mode, 0, 8);
 	sp->mode = strtol(dblock.dbuf.mode, 0, 8);
@@ -260,13 +399,14 @@ getdir(void)
 	sp->length = strtol(dblock.dbuf.size, 0, 8);
 	sp->length = strtol(dblock.dbuf.size, 0, 8);
 	sp->mtime = strtol(dblock.dbuf.mtime, 0, 8);
 	sp->mtime = strtol(dblock.dbuf.mtime, 0, 8);
 	chksum = strtol(dblock.dbuf.chksum, 0, 8);
 	chksum = strtol(dblock.dbuf.chksum, 0, 8);
-	if (chksum != checksum()) {
-		fprint(2, "directory checksum error\n");
-		exits("checksum error");
-	}
+	if (chksum != checksum())
+		sysfatal("header checksum error");
 	sp->qid.type = 0;
 	sp->qid.type = 0;
+	ustar = isustar(&dblock.dbuf);
+	getfullname(&dblock.dbuf);
 	/* the mode test is ugly but sometimes necessary */
 	/* the mode test is ugly but sometimes necessary */
-	if (dblock.dbuf.linkflag == '5' || (sp->mode&0170000) == 040000) {
+	if (dblock.dbuf.linkflag == LF_DIR || (sp->mode&0170000) == 040000 ||
+	    strrchr(fullname, '\0')[-1] == '/') {
 		sp->qid.type |= QTDIR;
 		sp->qid.type |= QTDIR;
 		sp->mode |= DMDIR;
 		sp->mode |= DMDIR;
 	}
 	}
@@ -278,8 +418,13 @@ passtar(void)
 	long blocks;
 	long blocks;
 	char buf[TBLOCK];
 	char buf[TBLOCK];
 
 
-	if (dblock.dbuf.linkflag == '1' || dblock.dbuf.linkflag == 's')
+	switch (dblock.dbuf.linkflag) {
+	case LF_LINK:
+	case LF_SYMLINK1:
+	case LF_SYMLINK2:
+	case LF_FIFO:
 		return;
 		return;
+	}
 	blocks = stbuf->length;
 	blocks = stbuf->length;
 	blocks += TBLOCK-1;
 	blocks += TBLOCK-1;
 	blocks /= TBLOCK;
 	blocks /= TBLOCK;
@@ -296,7 +441,7 @@ putfile(char *dir, char *longname, char *sname)
 	char buf[TBLOCK];
 	char buf[TBLOCK];
 	char curdir[4096];
 	char curdir[4096];
 	char shortname[4096];
 	char shortname[4096];
-	char *cp, *cp2;
+	char *cp;
 	Dir *db;
 	Dir *db;
 	int i, n;
 	int i, n;
 
 
@@ -321,17 +466,17 @@ putfile(char *dir, char *longname, char *sname)
 		for (i = 0, cp = buf; *cp++ = longname[i++];);
 		for (i = 0, cp = buf; *cp++ = longname[i++];);
 		*--cp = '/';
 		*--cp = '/';
 		*++cp = 0;
 		*++cp = 0;
-		if( (cp - buf) >= NAMSIZ) {
-			fprint(2, "tar: %s: file name too long\n", longname);
-			close(infile);
-			return;
-		}
 		stbuf->length = 0;
 		stbuf->length = 0;
+
 		tomodes(stbuf);
 		tomodes(stbuf);
-		strcpy(dblock.dbuf.name,buf);
-		dblock.dbuf.linkflag = '5';		/* Directory */
+		if (putfullname(&dblock.dbuf, buf) < 0) {
+			close(infile);
+			return;		/* putfullname already complained */
+		}
+		dblock.dbuf.linkflag = LF_DIR;
 		sprint(dblock.dbuf.chksum, "%6o", checksum());
 		sprint(dblock.dbuf.chksum, "%6o", checksum());
 		writetar( (char *) &dblock);
 		writetar( (char *) &dblock);
+
 		if (chdir(shortname) < 0) {
 		if (chdir(shortname) < 0) {
 			fprint(2, "tar: can't cd to %s: %r\n", shortname);
 			fprint(2, "tar: can't cd to %s: %r\n", shortname);
 			snprint(curdir, sizeof(curdir), "cd %s", shortname);
 			snprint(curdir, sizeof(curdir), "cd %s", shortname);
@@ -342,7 +487,8 @@ putfile(char *dir, char *longname, char *sname)
 			for(i = 0; i < n; i++){
 			for(i = 0; i < n; i++){
 				strncpy(cp, db[i].name, sizeof buf - (cp-buf));
 				strncpy(cp, db[i].name, sizeof buf - (cp-buf));
 				putfile(curdir, buf, db[i].name);
 				putfile(curdir, buf, db[i].name);
-			}free(db);
+			}
+			free(db);
 		}
 		}
 		close(infile);
 		close(infile);
 		if (chdir(dir) < 0 && chdir("..") < 0) {
 		if (chdir(dir) < 0 && chdir("..") < 0) {
@@ -353,26 +499,22 @@ putfile(char *dir, char *longname, char *sname)
 		return;
 		return;
 	}
 	}
 
 
-
+	/* plain file; write header block first */
 	tomodes(stbuf);
 	tomodes(stbuf);
-
-	cp2 = longname;
-	for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++);
-	if (i >= NAMSIZ) {
-		fprint(2, "%s: file name too long\n", longname);
+	if (putfullname(&dblock.dbuf, longname) < 0) {
 		close(infile);
 		close(infile);
-		return;
+		return;		/* putfullname already complained */
 	}
 	}
-
 	blocks = (stbuf->length + (TBLOCK-1)) / TBLOCK;
 	blocks = (stbuf->length + (TBLOCK-1)) / TBLOCK;
 	if (vflag) {
 	if (vflag) {
 		fprint(2, "a %s ", longname);
 		fprint(2, "a %s ", longname);
 		fprint(2, "%ld blocks\n", blocks);
 		fprint(2, "%ld blocks\n", blocks);
 	}
 	}
-	dblock.dbuf.linkflag = 0;			/* Regular file */
+	dblock.dbuf.linkflag = LF_PLAIN1;
 	sprint(dblock.dbuf.chksum, "%6o", checksum());
 	sprint(dblock.dbuf.chksum, "%6o", checksum());
 	writetar( (char *) &dblock);
 	writetar( (char *) &dblock);
 
 
+	/* then copy contents */
 	while ((i = readn(infile, buf, TBLOCK)) > 0 && blocks > 0) {
 	while ((i = readn(infile, buf, TBLOCK)) > 0 && blocks > 0) {
 		writetar(buf);
 		writetar(buf);
 		blocks--;
 		blocks--;
@@ -389,8 +531,9 @@ void
 doxtract(char **argv)
 doxtract(char **argv)
 {
 {
 	Dir null;
 	Dir null;
+	int wrsize;
 	long blocks, bytes;
 	long blocks, bytes;
-	char buf[TBLOCK], outname[NAMSIZ+4];
+	char buf[TBLOCK], outname[Maxname+3+1];
 	char **cp;
 	char **cp;
 	int ofile;
 	int ofile;
 
 
@@ -403,29 +546,30 @@ doxtract(char **argv)
 			goto gotit;
 			goto gotit;
 
 
 		for (cp = argv; *cp; cp++)
 		for (cp = argv; *cp; cp++)
-			if (prefix(*cp, dblock.dbuf.name))
+			if (prefix(*cp, fullname))
 				goto gotit;
 				goto gotit;
 		passtar();
 		passtar();
 		continue;
 		continue;
 
 
 gotit:
 gotit:
-		if(checkdir(dblock.dbuf.name, stbuf->mode, &(stbuf->qid)))
+		if(checkdir(fullname, stbuf->mode, &stbuf->qid))
 			continue;
 			continue;
 
 
-		if (dblock.dbuf.linkflag == '1') {
+		if (dblock.dbuf.linkflag == LF_LINK) {
 			fprint(2, "tar: can't link %s %s\n",
 			fprint(2, "tar: can't link %s %s\n",
-				dblock.dbuf.linkname, dblock.dbuf.name);
-			remove(dblock.dbuf.name);
+				dblock.dbuf.linkname, fullname);
+			remove(fullname);
 			continue;
 			continue;
 		}
 		}
-		if (dblock.dbuf.linkflag == 's') {
-			fprint(2, "tar: %s: cannot symlink\n", dblock.dbuf.name);
+		if (dblock.dbuf.linkflag == LF_SYMLINK1 ||
+		    dblock.dbuf.linkflag == LF_SYMLINK2) {
+			fprint(2, "tar: %s: cannot symlink\n", fullname);
 			continue;
 			continue;
 		}
 		}
-		if(dblock.dbuf.name[0] != '/' || Rflag)
-			sprint(outname, "./%s", dblock.dbuf.name);
+		if(fullname[0] != '/' || Rflag)
+			sprint(outname, "./%s", fullname);
 		else
 		else
-			strcpy(outname, dblock.dbuf.name);
+			strcpy(outname, fullname);
 		if ((ofile = create(outname, OWRITE, stbuf->mode & 0777)) < 0) {
 		if ((ofile = create(outname, OWRITE, stbuf->mode & 0777)) < 0) {
 			fprint(2, "tar: %s - cannot create: %r\n", outname);
 			fprint(2, "tar: %s - cannot create: %r\n", outname);
 			passtar();
 			passtar();
@@ -434,20 +578,16 @@ gotit:
 
 
 		blocks = ((bytes = stbuf->length) + TBLOCK-1)/TBLOCK;
 		blocks = ((bytes = stbuf->length) + TBLOCK-1)/TBLOCK;
 		if (vflag)
 		if (vflag)
-			fprint(2, "x %s, %ld bytes\n",
-				dblock.dbuf.name, bytes);
+			fprint(2, "x %s, %ld bytes\n", fullname, bytes);
 		while (blocks-- > 0) {
 		while (blocks-- > 0) {
 			readtar(buf);
 			readtar(buf);
-			if (bytes > TBLOCK) {
-				if (write(ofile, buf, TBLOCK) < 0) {
-					fprint(2, "tar: %s: HELP - extract write error: %r\n", dblock.dbuf.name);
-					exits("extract write");
-				}
-			} else
-				if (write(ofile, buf, bytes) < 0) {
-					fprint(2, "tar: %s: HELP - extract write error: %r\n", dblock.dbuf.name);
-					exits("extract write");
-				}
+			wrsize = (bytes > TBLOCK? TBLOCK: bytes);
+			if (write(ofile, buf, wrsize) != wrsize) {
+				fprint(2,
+				    "tar: %s: HELP - extract write error: %r\n",
+					fullname);
+				exits("extract write");
+			}
 			bytes -= TBLOCK;
 			bytes -= TBLOCK;
 		}
 		}
 		if(Tflag){
 		if(Tflag){
@@ -468,7 +608,7 @@ dotable(void)
 			break;
 			break;
 		if (vflag)
 		if (vflag)
 			longt(stbuf);
 			longt(stbuf);
-		Bprint(&bout, "%s", dblock.dbuf.name);
+		Bprint(&bout, "%s", fullname);
 		if (dblock.dbuf.linkflag == '1')
 		if (dblock.dbuf.linkflag == '1')
 			Bprint(&bout, " linked to %s", dblock.dbuf.linkname);
 			Bprint(&bout, " linked to %s", dblock.dbuf.linkname);
 		if (dblock.dbuf.linkflag == 's')
 		if (dblock.dbuf.linkflag == 's')
@@ -539,15 +679,17 @@ checkdir(char *name, int mode, Qid *qid)
 void
 void
 tomodes(Dir *sp)
 tomodes(Dir *sp)
 {
 {
-	char *cp;
-
-	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
-		*cp = '\0';
+	memset(dblock.dummy, 0, sizeof(dblock.dummy));
 	sprint(dblock.dbuf.mode, "%6lo ", sp->mode & 0777);
 	sprint(dblock.dbuf.mode, "%6lo ", sp->mode & 0777);
 	sprint(dblock.dbuf.uid, "%6o ", uflag);
 	sprint(dblock.dbuf.uid, "%6o ", uflag);
 	sprint(dblock.dbuf.gid, "%6o ", gflag);
 	sprint(dblock.dbuf.gid, "%6o ", gflag);
 	sprint(dblock.dbuf.size, "%11llo ", sp->length);
 	sprint(dblock.dbuf.size, "%11llo ", sp->length);
 	sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime);
 	sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime);
+	if (posix) {
+		setustar(&dblock.dbuf);
+		strncpy(dblock.dbuf.uname, sp->uid, sizeof dblock.dbuf.uname);
+		strncpy(dblock.dbuf.gname, sp->gid, sizeof dblock.dbuf.gname);
+	}
 }
 }
 
 
 int
 int

+ 32 - 21
sys/src/cmd/upas/common/libsys.c

@@ -884,6 +884,36 @@ remoteaddr(int fd, char *dir)
 	return "";
 	return "";
 }
 }
 
 
+//  create a file and 
+//	1) ensure the modes we asked for
+//	2) make gid == uid
+static int
+docreate(char *file, int perm)
+{
+	int fd;
+	Dir ndir;
+	Dir *d;
+
+	//  create the mbox
+	fd = create(file, OREAD, perm);
+	if(fd < 0){
+		fprint(2, "couldn't create %s\n", file);
+		return -1;
+	}
+	d = dirfstat(fd);
+	if(d == nil){
+		fprint(2, "couldn't stat %s\n", file);
+		return -1;
+	}
+	nulldir(&ndir);
+	ndir.mode = perm;
+	ndir.gid = d->uid;
+	if(dirfwstat(fd, &ndir) < 0)
+		fprint(2, "couldn't chmod %s: %r\n", file);
+	close(fd);
+	return 0;
+}
+
 //  create a mailbox
 //  create a mailbox
 int
 int
 creatembox(char *user, char *folder)
 creatembox(char *user, char *folder)
@@ -891,8 +921,6 @@ creatembox(char *user, char *folder)
 	char *p;
 	char *p;
 	String *mailfile;
 	String *mailfile;
 	char buf[512];
 	char buf[512];
-	int fd;
-	Dir *d;
 	Mlock *ml;
 	Mlock *ml;
 
 
 	mailfile = s_new();
 	mailfile = s_new();
@@ -919,32 +947,15 @@ creatembox(char *user, char *folder)
 			break;
 			break;
 		*p = 0;
 		*p = 0;
 		if(access(s_to_c(mailfile), 0) != 0){
 		if(access(s_to_c(mailfile), 0) != 0){
-			if((fd = create(s_to_c(mailfile), OREAD, DMDIR|0711)) < 0){
-				fprint(2, "couldn't create %s\n", s_to_c(mailfile));
+			if(docreate(s_to_c(mailfile), DMDIR|0711) < 0)
 				return -1;
 				return -1;
-			}
-			close(fd);
 		}
 		}
 		*p = '/';
 		*p = '/';
 	}
 	}
 
 
 	//  create the mbox
 	//  create the mbox
-	fd = create(s_to_c(mailfile), OREAD, 0622|DMAPPEND|DMEXCL);
-	if(fd < 0){
-		fprint(2, "couldn't create %s\n", s_to_c(mailfile));
-		return -1;
-	}
-	d = dirfstat(fd);
-	if(d == nil){
-		close(fd);
-		fprint(2, "couldn't chmod %s\n", s_to_c(mailfile));
+	if(docreate(s_to_c(mailfile), 0622|DMAPPEND|DMEXCL) < 0)
 		return -1;
 		return -1;
-	}
-	d->mode = 0622|DMAPPEND|DMEXCL;
-	if(dirfwstat(fd, d) < 0)
-		fprint(2, "couldn't chmod %s\n", s_to_c(mailfile));
-	free(d);
-	close(fd);
 
 
 	/*
 	/*
 	 *  create the lock file if it doesn't exist
 	 *  create the lock file if it doesn't exist