History

add hg and python

cinap_lenrek committed 15 years ago

Commit 4bb9e221 parent 987265c3706 files · +1228772 −-233Browse files

Showing the changes to sys/src/cmd/python (894 of 3706 files). Show all

Unified · Split

894 files
  1. sys/src/cmd/python/Demo/README +61 −0
  2. sys/src/cmd/python/Demo/cgi/README +11 −0
  3. sys/src/cmd/python/Demo/cgi/cgi0.sh +8 −0
  4. sys/src/cmd/python/Demo/cgi/cgi1.py +14 −0
  5. sys/src/cmd/python/Demo/cgi/cgi2.py +22 −0
  6. sys/src/cmd/python/Demo/cgi/cgi3.py +10 −0
  7. sys/src/cmd/python/Demo/cgi/wiki.py +123 −0
  8. sys/src/cmd/python/Demo/classes/Complex.py +320 −0
  9. sys/src/cmd/python/Demo/classes/Dates.py +222 −0
  10. sys/src/cmd/python/Demo/classes/Dbm.py +66 −0
  11. sys/src/cmd/python/Demo/classes/README +13 −0
  12. sys/src/cmd/python/Demo/classes/Range.py +93 −0
  13. sys/src/cmd/python/Demo/classes/Rat.py +310 −0
  14. sys/src/cmd/python/Demo/classes/Rev.py +95 −0
  15. sys/src/cmd/python/Demo/classes/Vec.py +54 −0
  16. sys/src/cmd/python/Demo/classes/bitvec.py +332 −0
  17. sys/src/cmd/python/Demo/comparisons/README +60 −0
  18. sys/src/cmd/python/Demo/comparisons/patterns +4 −0
  19. sys/src/cmd/python/Demo/comparisons/regextest.py +47 −0
  20. sys/src/cmd/python/Demo/comparisons/sortingtest.py +51 −0
  21. sys/src/cmd/python/Demo/comparisons/systemtest.py +74 −0
  22. sys/src/cmd/python/Demo/curses/README +25 −0
  23. sys/src/cmd/python/Demo/curses/life.py +216 −0
  24. sys/src/cmd/python/Demo/curses/ncurses.py +273 −0
  25. sys/src/cmd/python/Demo/curses/rain.py +94 −0
  26. sys/src/cmd/python/Demo/curses/repeat.py +58 −0
  27. sys/src/cmd/python/Demo/curses/tclock.py +147 −0
  28. sys/src/cmd/python/Demo/curses/xmas.py +906 −0
  29. sys/src/cmd/python/Demo/embed/Makefile +57 −0
  30. sys/src/cmd/python/Demo/embed/README +19 −0
  31. sys/src/cmd/python/Demo/embed/demo.c +65 −0
  32. sys/src/cmd/python/Demo/embed/importexc.c +17 −0
  33. sys/src/cmd/python/Demo/embed/loop.c +33 −0
  34. sys/src/cmd/python/Demo/imputil/importers.py +248 −0
  35. sys/src/cmd/python/Demo/imputil/knee.py +126 −0
  36. sys/src/cmd/python/Demo/md5test/README +10 −0
  37. sys/src/cmd/python/Demo/md5test/foo +1 −0
  38. sys/src/cmd/python/Demo/md5test/md5driver.py +123 −0
  39. sys/src/cmd/python/Demo/metaclasses/Eiffel.py +113 −0
  40. sys/src/cmd/python/Demo/metaclasses/Enum.py +169 −0
  41. sys/src/cmd/python/Demo/metaclasses/Meta.py +118 −0
  42. sys/src/cmd/python/Demo/metaclasses/Simple.py +45 −0
  43. sys/src/cmd/python/Demo/metaclasses/Synch.py +256 −0
  44. sys/src/cmd/python/Demo/metaclasses/Trace.py +144 −0
  45. sys/src/cmd/python/Demo/metaclasses/index.html +605 −0
  46. sys/src/cmd/python/Demo/metaclasses/meta-vladimir.txt +256 −0
  47. sys/src/cmd/python/Demo/newmetaclasses/Eiffel.py +141 −0
  48. sys/src/cmd/python/Demo/newmetaclasses/Enum.py +177 −0
  49. sys/src/cmd/python/Demo/parser/FILES +6 −0
  50. sys/src/cmd/python/Demo/parser/README +31 −0
  51. sys/src/cmd/python/Demo/parser/docstring.py +2 −0
  52. sys/src/cmd/python/Demo/parser/example.py +190 −0
  53. sys/src/cmd/python/Demo/parser/simple.py +1 −0
  54. sys/src/cmd/python/Demo/parser/source.py +27 −0
  55. sys/src/cmd/python/Demo/parser/test_parser.py +48 −0
  56. sys/src/cmd/python/Demo/parser/texipre.dat +100 −0
  57. sys/src/cmd/python/Demo/parser/unparse.py +519 −0
  58. sys/src/cmd/python/Demo/pdist/FSProxy.py +322 −0
  59. sys/src/cmd/python/Demo/pdist/RCSProxy.py +198 −0
  60. sys/src/cmd/python/Demo/pdist/README +121 −0
  61. sys/src/cmd/python/Demo/pdist/client.py +157 −0
  62. sys/src/cmd/python/Demo/pdist/cmdfw.py +144 −0
  63. sys/src/cmd/python/Demo/pdist/cmptree.py +208 −0
  64. sys/src/cmd/python/Demo/pdist/cvslib.py +364 −0
  65. sys/src/cmd/python/Demo/pdist/cvslock.py +280 −0
  66. sys/src/cmd/python/Demo/pdist/mac.py +19 −0
  67. sys/src/cmd/python/Demo/pdist/makechangelog.py +109 −0
  68. sys/src/cmd/python/Demo/pdist/rcsbump +33 −0
  69. sys/src/cmd/python/Demo/pdist/rcsclient.py +71 −0
  70. sys/src/cmd/python/Demo/pdist/rcslib.py +334 −0
  71. sys/src/cmd/python/Demo/pdist/rcvs +8 −0
  72. sys/src/cmd/python/Demo/pdist/rcvs.py +477 −0
  73. sys/src/cmd/python/Demo/pdist/rrcs +8 −0
  74. sys/src/cmd/python/Demo/pdist/rrcs.py +160 −0
  75. sys/src/cmd/python/Demo/pdist/security.py +33 −0
  76. sys/src/cmd/python/Demo/pdist/server.py +145 −0
  77. sys/src/cmd/python/Demo/pdist/sumtree.py +24 −0
  78. sys/src/cmd/python/Demo/pysvr/Makefile +57 −0
  79. sys/src/cmd/python/Demo/pysvr/README +9 −0
  80. sys/src/cmd/python/Demo/pysvr/pysvr.c +370 −0
  81. sys/src/cmd/python/Demo/pysvr/pysvr.py +124 −0
  82. sys/src/cmd/python/Demo/rpc/MANIFEST +10 −0
  83. sys/src/cmd/python/Demo/rpc/README +31 −0
  84. sys/src/cmd/python/Demo/rpc/T.py +22 −0
  85. sys/src/cmd/python/Demo/rpc/mountclient.py +202 −0
  86. sys/src/cmd/python/Demo/rpc/nfsclient.py +201 −0
  87. sys/src/cmd/python/Demo/rpc/rnusersclient.py +98 −0
  88. sys/src/cmd/python/Demo/rpc/rpc.py +893 −0
  89. sys/src/cmd/python/Demo/rpc/test +24 −0
  90. sys/src/cmd/python/Demo/rpc/xdr.py +200 −0
  91. sys/src/cmd/python/Demo/scripts/README +23 −0
  92. sys/src/cmd/python/Demo/scripts/beer.py +14 −0
  93. sys/src/cmd/python/Demo/scripts/eqfix.py +198 −0
  94. sys/src/cmd/python/Demo/scripts/fact.py +49 −0
  95. sys/src/cmd/python/Demo/scripts/find-uname.py +40 −0
  96. sys/src/cmd/python/Demo/scripts/from.py +35 −0
  97. sys/src/cmd/python/Demo/scripts/ftpstats.py +145 −0
  98. sys/src/cmd/python/Demo/scripts/lpwatch.py +110 −0
  99. sys/src/cmd/python/Demo/scripts/makedir.py +21 −0
  100. sys/src/cmd/python/Demo/scripts/markov.py +117 −0
  101. sys/src/cmd/python/Demo/scripts/mboxconvert.py +124 −0
  102. sys/src/cmd/python/Demo/scripts/mkrcs.py +61 −0
  103. sys/src/cmd/python/Demo/scripts/morse.py +149 −0
  104. sys/src/cmd/python/Demo/scripts/newslist.doc +59 −0
  105. sys/src/cmd/python/Demo/scripts/newslist.py +366 −0
  106. sys/src/cmd/python/Demo/scripts/pi.py +34 −0
  107. sys/src/cmd/python/Demo/scripts/pp.py +130 −0
  108. sys/src/cmd/python/Demo/scripts/primes.py +27 −0
  109. sys/src/cmd/python/Demo/scripts/queens.py +85 −0
  110. sys/src/cmd/python/Demo/scripts/script.py +33 −0
  111. sys/src/cmd/python/Demo/scripts/unbirthday.py +107 −0
  112. sys/src/cmd/python/Demo/scripts/update.py +92 −0
  113. sys/src/cmd/python/Demo/scripts/wh.py +2 −0
  114. sys/src/cmd/python/Demo/sockets/README +21 −0
  115. sys/src/cmd/python/Demo/sockets/broadcast.py +15 −0
  116. sys/src/cmd/python/Demo/sockets/echosvr.py +31 −0
  117. sys/src/cmd/python/Demo/sockets/finger.py +58 −0
  118. sys/src/cmd/python/Demo/sockets/ftp.py +146 −0
  119. sys/src/cmd/python/Demo/sockets/gopher.py +347 −0
  120. sys/src/cmd/python/Demo/sockets/mcast.py +93 −0
  121. sys/src/cmd/python/Demo/sockets/radio.py +14 −0
  122. sys/src/cmd/python/Demo/sockets/rpython.py +35 −0
  123. sys/src/cmd/python/Demo/sockets/rpythond.py +52 −0
  124. sys/src/cmd/python/Demo/sockets/telnet.py +109 −0
  125. sys/src/cmd/python/Demo/sockets/throughput.py +93 −0
  126. sys/src/cmd/python/Demo/sockets/udpecho.py +63 −0
  127. sys/src/cmd/python/Demo/sockets/unicast.py +14 −0
  128. sys/src/cmd/python/Demo/sockets/unixclient.py +12 −0
  129. sys/src/cmd/python/Demo/sockets/unixserver.py +24 −0
  130. sys/src/cmd/python/Demo/threads/Coroutine.py +159 −0
  131. sys/src/cmd/python/Demo/threads/Generator.py +84 −0
  132. sys/src/cmd/python/Demo/threads/README +13 −0
  133. sys/src/cmd/python/Demo/threads/fcmp.py +64 −0
  134. sys/src/cmd/python/Demo/threads/find.py +155 −0
  135. sys/src/cmd/python/Demo/threads/squasher.py +105 −0
  136. sys/src/cmd/python/Demo/threads/sync.py +603 −0
  137. sys/src/cmd/python/Demo/threads/telnet.py +114 −0
  138. sys/src/cmd/python/Demo/tix/INSTALL.txt +89 −0
  139. sys/src/cmd/python/Demo/tix/README.txt +19 −0
  140. sys/src/cmd/python/Demo/tix/bitmaps/about.xpm +50 −0
  141. sys/src/cmd/python/Demo/tix/bitmaps/bold.xbm +6 −0
  142. sys/src/cmd/python/Demo/tix/bitmaps/capital.xbm +6 −0
  143. sys/src/cmd/python/Demo/tix/bitmaps/centerj.xbm +6 −0
  144. sys/src/cmd/python/Demo/tix/bitmaps/combobox.xbm +14 −0
  145. sys/src/cmd/python/Demo/tix/bitmaps/combobox.xpm +49 −0
  146. sys/src/cmd/python/Demo/tix/bitmaps/drivea.xbm +14 −0
  147. sys/src/cmd/python/Demo/tix/bitmaps/drivea.xpm +43 −0
  148. sys/src/cmd/python/Demo/tix/bitmaps/exit.xpm +48 −0
  149. sys/src/cmd/python/Demo/tix/bitmaps/filebox.xbm +14 −0
  150. sys/src/cmd/python/Demo/tix/bitmaps/filebox.xpm +49 −0
  151. sys/src/cmd/python/Demo/tix/bitmaps/italic.xbm +6 −0
  152. sys/src/cmd/python/Demo/tix/bitmaps/justify.xbm +6 −0
  153. sys/src/cmd/python/Demo/tix/bitmaps/leftj.xbm +6 −0
  154. sys/src/cmd/python/Demo/tix/bitmaps/netw.xbm +14 −0
  155. sys/src/cmd/python/Demo/tix/bitmaps/netw.xpm +45 −0
  156. sys/src/cmd/python/Demo/tix/bitmaps/optmenu.xpm +48 −0
  157. sys/src/cmd/python/Demo/tix/bitmaps/rightj.xbm +6 −0
  158. sys/src/cmd/python/Demo/tix/bitmaps/select.xpm +52 −0
  159. sys/src/cmd/python/Demo/tix/bitmaps/tix.gif +0 −0
  160. sys/src/cmd/python/Demo/tix/bitmaps/underline.xbm +6 −0
  161. sys/src/cmd/python/Demo/tix/grid.py +28 −0
  162. sys/src/cmd/python/Demo/tix/samples/Balloon.py +68 −0
  163. sys/src/cmd/python/Demo/tix/samples/BtnBox.py +44 −0
  164. sys/src/cmd/python/Demo/tix/samples/CmpImg.py +196 −0
  165. sys/src/cmd/python/Demo/tix/samples/ComboBox.py +102 −0
  166. sys/src/cmd/python/Demo/tix/samples/Control.py +122 −0
  167. sys/src/cmd/python/Demo/tix/samples/DirList.py +131 −0
  168. sys/src/cmd/python/Demo/tix/samples/DirTree.py +117 −0
  169. sys/src/cmd/python/Demo/tix/samples/NoteBook.py +119 −0
  170. sys/src/cmd/python/Demo/tix/samples/OptMenu.py +68 −0
  171. sys/src/cmd/python/Demo/tix/samples/PanedWin.py +98 −0
  172. sys/src/cmd/python/Demo/tix/samples/PopMenu.py +57 −0
  173. sys/src/cmd/python/Demo/tix/samples/SHList1.py +131 −0
  174. sys/src/cmd/python/Demo/tix/samples/SHList2.py +168 −0
  175. sys/src/cmd/python/Demo/tix/samples/Tree.py +80 −0
  176. sys/src/cmd/python/Demo/tix/tixwidgets.py +1003 −0
  177. sys/src/cmd/python/Demo/tkinter/README +10 −0
  178. sys/src/cmd/python/Demo/tkinter/guido/AttrDialog.py +452 −0
  179. sys/src/cmd/python/Demo/tkinter/guido/ManPage.py +220 −0
  180. sys/src/cmd/python/Demo/tkinter/guido/MimeViewer.py +143 −0
  181. sys/src/cmd/python/Demo/tkinter/guido/ShellWindow.py +151 −0
  182. sys/src/cmd/python/Demo/tkinter/guido/brownian.py +50 −0
  183. sys/src/cmd/python/Demo/tkinter/guido/canvasevents.py +244 −0
  184. sys/src/cmd/python/Demo/tkinter/guido/dialog.py +109 −0
  185. sys/src/cmd/python/Demo/tkinter/guido/electrons.py +91 −0
  186. sys/src/cmd/python/Demo/tkinter/guido/hanoi.py +154 −0
  187. sys/src/cmd/python/Demo/tkinter/guido/hello.py +17 −0
  188. sys/src/cmd/python/Demo/tkinter/guido/imagedraw.py +23 −0
  189. sys/src/cmd/python/Demo/tkinter/guido/imageview.py +12 −0
  190. sys/src/cmd/python/Demo/tkinter/guido/kill.py +98 −0
  191. sys/src/cmd/python/Demo/tkinter/guido/listtree.py +37 −0
  192. sys/src/cmd/python/Demo/tkinter/guido/mbox.py +285 −0
  193. sys/src/cmd/python/Demo/tkinter/guido/newmenubardemo.py +47 −0
  194. sys/src/cmd/python/Demo/tkinter/guido/optionmenu.py +27 −0
  195. sys/src/cmd/python/Demo/tkinter/guido/paint.py +60 −0
  196. sys/src/cmd/python/Demo/tkinter/guido/rmt.py +159 −0
  197. sys/src/cmd/python/Demo/tkinter/guido/solitaire.py +637 −0
  198. sys/src/cmd/python/Demo/tkinter/guido/sortvisu.py +634 −0
  199. sys/src/cmd/python/Demo/tkinter/guido/ss1.py +845 −0
  200. sys/src/cmd/python/Demo/tkinter/guido/svkill.py +128 −0
  201. sys/src/cmd/python/Demo/tkinter/guido/switch.py +55 −0
  202. sys/src/cmd/python/Demo/tkinter/guido/tkman.py +267 −0
  203. sys/src/cmd/python/Demo/tkinter/guido/wish.py +27 −0
  204. sys/src/cmd/python/Demo/tkinter/matt/00-HELLO-WORLD.py +27 −0
  205. sys/src/cmd/python/Demo/tkinter/matt/README +30 −0
  206. sys/src/cmd/python/Demo/tkinter/matt/animation-simple.py +35 −0
  207. sys/src/cmd/python/Demo/tkinter/matt/animation-w-velocity-ctrl.py +44 −0
  208. sys/src/cmd/python/Demo/tkinter/matt/bind-w-mult-calls-p-type.py +44 −0
  209. sys/src/cmd/python/Demo/tkinter/matt/canvas-demo-simple.py +28 −0
  210. sys/src/cmd/python/Demo/tkinter/matt/canvas-gridding.py +61 −0
  211. sys/src/cmd/python/Demo/tkinter/matt/canvas-moving-or-creating.py +62 −0
  212. sys/src/cmd/python/Demo/tkinter/matt/canvas-moving-w-mouse.py +55 −0
  213. sys/src/cmd/python/Demo/tkinter/matt/canvas-mult-item-sel.py +78 −0
  214. sys/src/cmd/python/Demo/tkinter/matt/canvas-reading-tag-info.py +49 −0
  215. sys/src/cmd/python/Demo/tkinter/matt/canvas-w-widget-draw-el.py +36 −0
  216. sys/src/cmd/python/Demo/tkinter/matt/canvas-with-scrollbars.py +60 −0
  217. sys/src/cmd/python/Demo/tkinter/matt/dialog-box.py +64 −0
  218. sys/src/cmd/python/Demo/tkinter/matt/entry-simple.py +24 −0
  219. sys/src/cmd/python/Demo/tkinter/matt/entry-with-shared-variable.py +46 −0
  220. sys/src/cmd/python/Demo/tkinter/matt/killing-window-w-wm.py +42 −0
  221. sys/src/cmd/python/Demo/tkinter/matt/menu-all-types-of-entries.py +244 −0
  222. sys/src/cmd/python/Demo/tkinter/matt/menu-simple.py +112 −0
  223. sys/src/cmd/python/Demo/tkinter/matt/not-what-you-might-think-1.py +28 −0
  224. sys/src/cmd/python/Demo/tkinter/matt/not-what-you-might-think-2.py +30 −0
  225. sys/src/cmd/python/Demo/tkinter/matt/packer-and-placer-together.py +41 −0
  226. sys/src/cmd/python/Demo/tkinter/matt/packer-simple.py +32 −0
  227. sys/src/cmd/python/Demo/tkinter/matt/placer-simple.py +39 −0
  228. sys/src/cmd/python/Demo/tkinter/matt/pong-demo-1.py +54 −0
  229. sys/src/cmd/python/Demo/tkinter/matt/printing-coords-of-items.py +61 −0
  230. sys/src/cmd/python/Demo/tkinter/matt/radiobutton-simple.py +62 −0
  231. sys/src/cmd/python/Demo/tkinter/matt/rubber-band-box-demo-1.py +58 −0
  232. sys/src/cmd/python/Demo/tkinter/matt/rubber-line-demo-1.py +51 −0
  233. sys/src/cmd/python/Demo/tkinter/matt/slider-demo-1.py +36 −0
  234. sys/src/cmd/python/Demo/tkinter/matt/subclass-existing-widgets.py +28 −0
  235. sys/src/cmd/python/Demo/tkinter/matt/two-radio-groups.py +110 −0
  236. sys/src/cmd/python/Demo/tkinter/matt/window-creation-more.py +35 −0
  237. sys/src/cmd/python/Demo/tkinter/matt/window-creation-simple.py +31 −0
  238. sys/src/cmd/python/Demo/tkinter/matt/window-creation-w-location.py +45 −0
  239. sys/src/cmd/python/Demo/xml/elem_count.py +36 −0
  240. sys/src/cmd/python/Demo/xml/roundtrip.py +45 −0
  241. sys/src/cmd/python/Demo/xml/rss2html.py +91 −0
  242. sys/src/cmd/python/Demo/zlib/minigzip.py +133 −0
  243. sys/src/cmd/python/Demo/zlib/zlibdemo.py +48 −0
  244. sys/src/cmd/python/Demo/zlib/zlibdemo.py.gz +0 −0
  245. sys/src/cmd/python/Doc/ACKS +202 −0
  246. sys/src/cmd/python/Doc/Makefile +736 −0
  247. sys/src/cmd/python/Doc/Makefile.deps +386 −0
  248. sys/src/cmd/python/Doc/README +246 −0
  249. sys/src/cmd/python/Doc/TODO +74 −0
  250. sys/src/cmd/python/Doc/api/abstract.tex +1057 −0
  251. sys/src/cmd/python/Doc/api/api.tex +60 −0
  252. sys/src/cmd/python/Doc/api/concrete.tex +3203 −0
  253. sys/src/cmd/python/Doc/api/exceptions.tex +442 −0
  254. sys/src/cmd/python/Doc/api/init.tex +884 −0
  255. sys/src/cmd/python/Doc/api/intro.tex +627 −0
  256. sys/src/cmd/python/Doc/api/memory.tex +204 −0
  257. sys/src/cmd/python/Doc/api/newtypes.tex +1780 −0
  258. sys/src/cmd/python/Doc/api/refcounting.tex +69 −0
  259. sys/src/cmd/python/Doc/api/refcounts.dat +1756 −0
  260. sys/src/cmd/python/Doc/api/utilities.tex +1023 −0
  261. sys/src/cmd/python/Doc/api/veryhigh.tex +287 −0
  262. sys/src/cmd/python/Doc/commontex/boilerplate.tex +9 −0
  263. sys/src/cmd/python/Doc/commontex/copyright.tex +14 −0
  264. sys/src/cmd/python/Doc/commontex/license.tex +673 −0
  265. sys/src/cmd/python/Doc/commontex/reportingbugs.tex +61 −0
  266. sys/src/cmd/python/Doc/commontex/typestruct.h +76 −0
  267. sys/src/cmd/python/Doc/dist/dist.tex +3795 −0
  268. sys/src/cmd/python/Doc/dist/sysconfig.tex +113 −0
  269. sys/src/cmd/python/Doc/doc/doc.tex +2129 −0
  270. sys/src/cmd/python/Doc/ext/building.tex +143 −0
  271. sys/src/cmd/python/Doc/ext/embedding.tex +316 −0
  272. sys/src/cmd/python/Doc/ext/ext.tex +67 −0
  273. sys/src/cmd/python/Doc/ext/extending.tex +1390 −0
  274. sys/src/cmd/python/Doc/ext/newtypes.tex +1765 −0
  275. sys/src/cmd/python/Doc/ext/noddy.c +54 −0
  276. sys/src/cmd/python/Doc/ext/noddy2.c +190 −0
  277. sys/src/cmd/python/Doc/ext/noddy3.c +243 −0
  278. sys/src/cmd/python/Doc/ext/noddy4.c +224 −0
  279. sys/src/cmd/python/Doc/ext/run-func.c +68 −0
  280. sys/src/cmd/python/Doc/ext/setup.py +8 −0
  281. sys/src/cmd/python/Doc/ext/shoddy.c +91 −0
  282. sys/src/cmd/python/Doc/ext/test.py +213 −0
  283. sys/src/cmd/python/Doc/ext/windows.tex +320 −0
  284. sys/src/cmd/python/Doc/howto/Makefile +84 −0
  285. sys/src/cmd/python/Doc/howto/TODO +13 −0
  286. sys/src/cmd/python/Doc/howto/advocacy.tex +411 −0
  287. sys/src/cmd/python/Doc/howto/curses.tex +485 −0
  288. sys/src/cmd/python/Doc/howto/doanddont.tex +344 −0
  289. sys/src/cmd/python/Doc/howto/regex.tex +1463 −0
  290. sys/src/cmd/python/Doc/howto/sockets.tex +465 −0
  291. sys/src/cmd/python/Doc/howto/unicode.rst +766 −0
  292. sys/src/cmd/python/Doc/howto/urllib2.rst +598 −0
  293. sys/src/cmd/python/Doc/html/about.dat +24 −0
  294. sys/src/cmd/python/Doc/html/about.html +84 −0
  295. sys/src/cmd/python/Doc/html/icons/blank.gif +0 −0
  296. sys/src/cmd/python/Doc/html/icons/blank.png +0 −0
  297. sys/src/cmd/python/Doc/html/icons/contents.gif +0 −0
  298. sys/src/cmd/python/Doc/html/icons/contents.png +0 −0
  299. sys/src/cmd/python/Doc/html/icons/index.gif +0 −0
  300. sys/src/cmd/python/Doc/html/icons/index.png +0 −0
  301. sys/src/cmd/python/Doc/html/icons/modules.gif +0 −0
  302. sys/src/cmd/python/Doc/html/icons/modules.png +0 −0
  303. sys/src/cmd/python/Doc/html/icons/next.gif +0 −0
  304. sys/src/cmd/python/Doc/html/icons/next.png +0 −0
  305. sys/src/cmd/python/Doc/html/icons/previous.gif +0 −0
  306. sys/src/cmd/python/Doc/html/icons/previous.png +0 −0
  307. sys/src/cmd/python/Doc/html/icons/pyfav.gif +0 −0
  308. sys/src/cmd/python/Doc/html/icons/pyfav.png +0 −0
  309. sys/src/cmd/python/Doc/html/icons/up.gif +0 −0
  310. sys/src/cmd/python/Doc/html/icons/up.png +0 −0
  311. sys/src/cmd/python/Doc/html/index.html.in +140 −0
  312. sys/src/cmd/python/Doc/html/stdabout.dat +54 −0
  313. sys/src/cmd/python/Doc/html/style.css +243 −0
  314. sys/src/cmd/python/Doc/info/Makefile +82 −0
  315. sys/src/cmd/python/Doc/info/README +21 −0
  316. sys/src/cmd/python/Doc/info/python.dir +11 −0
  317. sys/src/cmd/python/Doc/inst/inst.tex +1112 −0
  318. sys/src/cmd/python/Doc/lib/archiving.tex +8 −0
  319. sys/src/cmd/python/Doc/lib/asttable.tex +283 −0
  320. sys/src/cmd/python/Doc/lib/caseless.py +60 −0
  321. sys/src/cmd/python/Doc/lib/compiler.tex +354 −0
  322. sys/src/cmd/python/Doc/lib/custominterp.tex +13 −0
  323. sys/src/cmd/python/Doc/lib/datatypes.tex +10 −0
  324. sys/src/cmd/python/Doc/lib/development.tex +13 −0
  325. sys/src/cmd/python/Doc/lib/distutils.tex +38 −0
  326. sys/src/cmd/python/Doc/lib/email-dir.py +115 −0
  327. sys/src/cmd/python/Doc/lib/email-mime.py +32 −0
  328. sys/src/cmd/python/Doc/lib/email-simple.py +25 −0
  329. sys/src/cmd/python/Doc/lib/email-unpack.py +68 −0
  330. sys/src/cmd/python/Doc/lib/email.tex +402 −0
  331. sys/src/cmd/python/Doc/lib/emailcharsets.tex +244 −0
  332. sys/src/cmd/python/Doc/lib/emailencoders.tex +47 −0
  333. sys/src/cmd/python/Doc/lib/emailexc.tex +87 −0
  334. sys/src/cmd/python/Doc/lib/emailgenerator.tex +133 −0
  335. sys/src/cmd/python/Doc/lib/emailheaders.tex +178 −0
  336. sys/src/cmd/python/Doc/lib/emailiter.tex +65 −0
  337. sys/src/cmd/python/Doc/lib/emailmessage.tex +561 −0
  338. sys/src/cmd/python/Doc/lib/emailmimebase.tex +186 −0
  339. sys/src/cmd/python/Doc/lib/emailparser.tex +208 −0
  340. sys/src/cmd/python/Doc/lib/emailutil.tex +157 −0
  341. sys/src/cmd/python/Doc/lib/fileformats.tex +7 −0
  342. sys/src/cmd/python/Doc/lib/filesys.tex +18 −0
  343. sys/src/cmd/python/Doc/lib/frameworks.tex +10 −0
  344. sys/src/cmd/python/Doc/lib/i18n.tex +11 −0
  345. sys/src/cmd/python/Doc/lib/internet.tex +13 −0
  346. sys/src/cmd/python/Doc/lib/ipc.tex +14 −0
  347. sys/src/cmd/python/Doc/lib/language.tex +10 −0
  348. sys/src/cmd/python/Doc/lib/lib.tex +487 −0
  349. sys/src/cmd/python/Doc/lib/libaifc.tex +202 −0
  350. sys/src/cmd/python/Doc/lib/libal.tex +181 −0
  351. sys/src/cmd/python/Doc/lib/liballos.tex +9 −0
  352. sys/src/cmd/python/Doc/lib/libamoeba.tex +132 −0
  353. sys/src/cmd/python/Doc/lib/libanydbm.tex +85 −0
  354. sys/src/cmd/python/Doc/lib/libarray.tex +241 −0
  355. sys/src/cmd/python/Doc/lib/libascii.tex +175 −0
  356. sys/src/cmd/python/Doc/lib/libast.tex +57 −0
  357. sys/src/cmd/python/Doc/lib/libasynchat.tex +254 −0
  358. sys/src/cmd/python/Doc/lib/libasyncore.tex +260 −0
  359. sys/src/cmd/python/Doc/lib/libatexit.tex +94 −0
  360. sys/src/cmd/python/Doc/lib/libaudioop.tex +259 −0
  361. sys/src/cmd/python/Doc/lib/libbase64.tex +169 −0
  362. sys/src/cmd/python/Doc/lib/libbasehttp.tex +245 −0
  363. sys/src/cmd/python/Doc/lib/libbastion.tex +57 −0
  364. sys/src/cmd/python/Doc/lib/libbinascii.tex +147 −0
  365. sys/src/cmd/python/Doc/lib/libbinhex.tex +55 −0
  366. sys/src/cmd/python/Doc/lib/libbisect.tex +84 −0
  367. sys/src/cmd/python/Doc/lib/libbltin.tex +44 −0
  368. sys/src/cmd/python/Doc/lib/libbsddb.tex +208 −0
  369. sys/src/cmd/python/Doc/lib/libbz2.tex +174 −0
  370. sys/src/cmd/python/Doc/lib/libcalendar.tex +304 −0
  371. sys/src/cmd/python/Doc/lib/libcd.tex +304 −0
  372. sys/src/cmd/python/Doc/lib/libcfgparser.tex +313 −0
  373. sys/src/cmd/python/Doc/lib/libcgi.tex +602 −0
  374. sys/src/cmd/python/Doc/lib/libcgihttp.tex +70 −0
  375. sys/src/cmd/python/Doc/lib/libcgitb.tex +67 −0
  376. sys/src/cmd/python/Doc/lib/libchunk.tex +111 −0
  377. sys/src/cmd/python/Doc/lib/libcmath.tex +142 −0
  378. sys/src/cmd/python/Doc/lib/libcmd.tex +198 −0
  379. sys/src/cmd/python/Doc/lib/libcmp.tex +36 −0
  380. sys/src/cmd/python/Doc/lib/libcmpcache.tex +21 −0
  381. sys/src/cmd/python/Doc/lib/libcode.tex +173 −0
  382. sys/src/cmd/python/Doc/lib/libcodecs.tex +1348 −0
  383. sys/src/cmd/python/Doc/lib/libcodeop.tex +103 −0
  384. sys/src/cmd/python/Doc/lib/libcollections.tex +341 −0
  385. sys/src/cmd/python/Doc/lib/libcolorsys.tex +54 −0
  386. sys/src/cmd/python/Doc/lib/libcommands.tex +62 −0
  387. sys/src/cmd/python/Doc/lib/libcompileall.tex +63 −0
  388. sys/src/cmd/python/Doc/lib/libconsts.tex +31 −0
  389. sys/src/cmd/python/Doc/lib/libcontextlib.tex +130 −0
  390. sys/src/cmd/python/Doc/lib/libcookie.tex +260 −0
  391. sys/src/cmd/python/Doc/lib/libcookielib.tex +720 −0
  392. sys/src/cmd/python/Doc/lib/libcopy.tex +97 −0
  393. sys/src/cmd/python/Doc/lib/libcopyreg.tex +40 −0
  394. sys/src/cmd/python/Doc/lib/libcrypt.tex +54 −0
  395. sys/src/cmd/python/Doc/lib/libcrypto.tex +19 −0
  396. sys/src/cmd/python/Doc/lib/libcsv.tex +538 −0
  397. sys/src/cmd/python/Doc/lib/libctypes.tex +2443 −0
  398. sys/src/cmd/python/Doc/lib/libcurses.tex +1395 −0
  399. sys/src/cmd/python/Doc/lib/libcursespanel.tex +96 −0
  400. sys/src/cmd/python/Doc/lib/libdatetime.tex +1441 −0
  401. sys/src/cmd/python/Doc/lib/libdbhash.tex +88 −0
  402. sys/src/cmd/python/Doc/lib/libdbm.tex +61 −0
  403. sys/src/cmd/python/Doc/lib/libdecimal.tex +1313 −0
  404. sys/src/cmd/python/Doc/lib/libdifflib.tex +704 −0
  405. sys/src/cmd/python/Doc/lib/libdircache.tex +49 −0
  406. sys/src/cmd/python/Doc/lib/libdis.tex +706 −0
  407. sys/src/cmd/python/Doc/lib/libdl.tex +101 −0
  408. sys/src/cmd/python/Doc/lib/libdoctest.tex +1949 −0
  409. sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex +105 −0
  410. sys/src/cmd/python/Doc/lib/libdumbdbm.tex +63 −0
  411. sys/src/cmd/python/Doc/lib/libdummythread.tex +22 −0
  412. sys/src/cmd/python/Doc/lib/libdummythreading.tex +22 −0
  413. sys/src/cmd/python/Doc/lib/liberrno.tex +149 −0
  414. sys/src/cmd/python/Doc/lib/libetree.tex +356 −0
  415. sys/src/cmd/python/Doc/lib/libexcs.tex +466 −0
  416. sys/src/cmd/python/Doc/lib/libfcntl.tex +174 −0
  417. sys/src/cmd/python/Doc/lib/libfilecmp.tex +142 −0
  418. sys/src/cmd/python/Doc/lib/libfileinput.tex +192 −0
  419. sys/src/cmd/python/Doc/lib/libfl.tex +507 −0
  420. sys/src/cmd/python/Doc/lib/libfm.tex +94 −0
  421. sys/src/cmd/python/Doc/lib/libfnmatch.tex +86 −0
  422. sys/src/cmd/python/Doc/lib/libformatter.tex +329 −0
  423. sys/src/cmd/python/Doc/lib/libfpectl.tex +127 −0
  424. sys/src/cmd/python/Doc/lib/libfpformat.tex +54 −0
  425. sys/src/cmd/python/Doc/lib/libftplib.tex +288 −0
  426. sys/src/cmd/python/Doc/lib/libfuncs.tex +1321 −0
  427. sys/src/cmd/python/Doc/lib/libfunctools.tex +132 −0
  428. sys/src/cmd/python/Doc/lib/libfuture.tex +69 −0
  429. sys/src/cmd/python/Doc/lib/libgc.tex +196 −0
  430. sys/src/cmd/python/Doc/lib/libgdbm.tex +100 −0
  431. sys/src/cmd/python/Doc/lib/libgetopt.tex +154 −0
  432. sys/src/cmd/python/Doc/lib/libgetpass.tex +36 −0
  433. sys/src/cmd/python/Doc/lib/libgettext.tex +773 −0
  434. sys/src/cmd/python/Doc/lib/libgl.tex +224 −0
  435. sys/src/cmd/python/Doc/lib/libglob.tex +51 −0
  436. sys/src/cmd/python/Doc/lib/libgopherlib.tex +36 −0
  437. sys/src/cmd/python/Doc/lib/libgrp.tex +49 −0
  438. sys/src/cmd/python/Doc/lib/libgzip.tex +70 −0
  439. sys/src/cmd/python/Doc/lib/libhashlib.tex +114 −0
  440. sys/src/cmd/python/Doc/lib/libheapq.tex +214 −0
  441. sys/src/cmd/python/Doc/lib/libhmac.tex +54 −0
  442. sys/src/cmd/python/Doc/lib/libhotshot.tex +137 −0
  443. sys/src/cmd/python/Doc/lib/libhtmllib.tex +181 −0
  444. sys/src/cmd/python/Doc/lib/libhtmlparser.tex +169 −0
  445. sys/src/cmd/python/Doc/lib/libhttplib.tex +434 −0
  446. sys/src/cmd/python/Doc/lib/libimageop.tex +100 −0
  447. sys/src/cmd/python/Doc/lib/libimaplib.tex +507 −0
  448. sys/src/cmd/python/Doc/lib/libimgfile.tex +66 −0
  449. sys/src/cmd/python/Doc/lib/libimghdr.tex +60 −0
  450. sys/src/cmd/python/Doc/lib/libimp.tex +291 −0
  451. sys/src/cmd/python/Doc/lib/libinspect.tex +393 −0
  452. sys/src/cmd/python/Doc/lib/libintro.tex +53 −0
  453. sys/src/cmd/python/Doc/lib/libitertools.tex +546 −0
  454. sys/src/cmd/python/Doc/lib/libjpeg.tex +80 −0
  455. sys/src/cmd/python/Doc/lib/libkeyword.tex +20 −0
  456. sys/src/cmd/python/Doc/lib/liblinecache.tex +50 −0
  457. sys/src/cmd/python/Doc/lib/liblocale.tex +527 −0
  458. sys/src/cmd/python/Doc/lib/liblogging.tex +1729 −0
  459. sys/src/cmd/python/Doc/lib/libmailbox.tex +1444 −0
  460. sys/src/cmd/python/Doc/lib/libmailcap.tex +82 −0
  461. sys/src/cmd/python/Doc/lib/libmain.tex +16 −0
  462. sys/src/cmd/python/Doc/lib/libmarshal.tex +117 −0
  463. sys/src/cmd/python/Doc/lib/libmath.tex +209 −0
  464. sys/src/cmd/python/Doc/lib/libmd5.tex +92 −0
  465. sys/src/cmd/python/Doc/lib/libmhlib.tex +168 −0
  466. sys/src/cmd/python/Doc/lib/libmimetools.tex +120 −0
  467. sys/src/cmd/python/Doc/lib/libmimetypes.tex +226 −0
  468. sys/src/cmd/python/Doc/lib/libmimewriter.tex +80 −0
  469. sys/src/cmd/python/Doc/lib/libmimify.tex +94 −0
  470. sys/src/cmd/python/Doc/lib/libmisc.tex +7 −0
  471. sys/src/cmd/python/Doc/lib/libmm.tex +8 −0
  472. sys/src/cmd/python/Doc/lib/libmmap.tex +171 −0
  473. sys/src/cmd/python/Doc/lib/libmodulefinder.tex +51 −0
  474. sys/src/cmd/python/Doc/lib/libmsilib.tex +485 −0
  475. sys/src/cmd/python/Doc/lib/libmsvcrt.tex +109 −0
  476. sys/src/cmd/python/Doc/lib/libmultifile.tex +175 −0
  477. sys/src/cmd/python/Doc/lib/libmutex.tex +57 −0
  478. sys/src/cmd/python/Doc/lib/libnetrc.tex +68 −0
  479. sys/src/cmd/python/Doc/lib/libnew.tex +63 −0
  480. sys/src/cmd/python/Doc/lib/libni.tex +63 −0
  481. sys/src/cmd/python/Doc/lib/libnis.tex +63 −0
  482. sys/src/cmd/python/Doc/lib/libnntplib.tex +355 −0
  483. sys/src/cmd/python/Doc/lib/libobjs.tex +24 −0
  484. sys/src/cmd/python/Doc/lib/liboperator.tex +530 −0
  485. sys/src/cmd/python/Doc/lib/liboptparse.tex +1888 −0
  486. sys/src/cmd/python/Doc/lib/libos.tex +2006 −0
  487. sys/src/cmd/python/Doc/lib/libossaudiodev.tex +401 −0
  488. sys/src/cmd/python/Doc/lib/libpanel.tex +74 −0
  489. sys/src/cmd/python/Doc/lib/libparser.tex +711 −0
  490. sys/src/cmd/python/Doc/lib/libpdb.tex +456 −0
  491. sys/src/cmd/python/Doc/lib/libpickle.tex +888 −0
  492. sys/src/cmd/python/Doc/lib/libpickletools.tex +34 −0
  493. sys/src/cmd/python/Doc/lib/libpipes.tex +84 −0
  494. sys/src/cmd/python/Doc/lib/libpkgutil.tex +45 −0
  495. sys/src/cmd/python/Doc/lib/libplatform.tex +221 −0
  496. sys/src/cmd/python/Doc/lib/libpopen2.tex +189 −0
  497. sys/src/cmd/python/Doc/lib/libpoplib.tex +181 −0
  498. sys/src/cmd/python/Doc/lib/libposix.tex +97 −0
  499. sys/src/cmd/python/Doc/lib/libposixfile.tex +175 −0
  500. sys/src/cmd/python/Doc/lib/libposixpath.tex +281 −0
  501. sys/src/cmd/python/Doc/lib/libpprint.tex +210 −0
  502. sys/src/cmd/python/Doc/lib/libprofile.tex +722 −0
  503. sys/src/cmd/python/Doc/lib/libpty.tex +44 −0
  504. sys/src/cmd/python/Doc/lib/libpwd.tex +57 −0
  505. sys/src/cmd/python/Doc/lib/libpyclbr.tex +102 −0
  506. sys/src/cmd/python/Doc/lib/libpycompile.tex +53 −0
  507. sys/src/cmd/python/Doc/lib/libpydoc.tex +67 −0
  508. sys/src/cmd/python/Doc/lib/libpyexpat.tex +777 −0
  509. sys/src/cmd/python/Doc/lib/libpython.tex +8 −0
  510. sys/src/cmd/python/Doc/lib/libqueue.tex +145 −0
  511. sys/src/cmd/python/Doc/lib/libquopri.tex +61 −0
  512. sys/src/cmd/python/Doc/lib/librandom.tex +309 −0
  513. sys/src/cmd/python/Doc/lib/libre.tex +954 −0
  514. sys/src/cmd/python/Doc/lib/libreadline.tex +196 −0
  515. sys/src/cmd/python/Doc/lib/librepr.tex +133 −0
  516. sys/src/cmd/python/Doc/lib/libresource.tex +215 −0
  517. sys/src/cmd/python/Doc/lib/librestricted.tex +66 −0
  518. sys/src/cmd/python/Doc/lib/librexec.tex +275 −0
  519. sys/src/cmd/python/Doc/lib/librfc822.tex +336 −0
  520. sys/src/cmd/python/Doc/lib/librgbimg.tex +54 −0
  521. sys/src/cmd/python/Doc/lib/librlcompleter.tex +65 −0
  522. sys/src/cmd/python/Doc/lib/librobotparser.tex +66 −0
  523. sys/src/cmd/python/Doc/lib/librunpy.tex +74 −0
  524. sys/src/cmd/python/Doc/lib/libsched.tex +97 −0
  525. sys/src/cmd/python/Doc/lib/libselect.tex +132 −0
  526. sys/src/cmd/python/Doc/lib/libsets.tex +264 −0
  527. sys/src/cmd/python/Doc/lib/libsgi.tex +7 −0
  528. sys/src/cmd/python/Doc/lib/libsgmllib.tex +271 −0
  529. sys/src/cmd/python/Doc/lib/libsha.tex +83 −0
  530. sys/src/cmd/python/Doc/lib/libshelve.tex +174 −0
  531. sys/src/cmd/python/Doc/lib/libshlex.tex +274 −0
  532. sys/src/cmd/python/Doc/lib/libshutil.tex +151 −0
  533. sys/src/cmd/python/Doc/lib/libsignal.tex +174 −0
  534. sys/src/cmd/python/Doc/lib/libsimplehttp.tex +86 −0
  535. sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex +228 −0
  536. sys/src/cmd/python/Doc/lib/libsite.tex +88 −0
  537. sys/src/cmd/python/Doc/lib/libsmtpd.tex +63 −0
  538. sys/src/cmd/python/Doc/lib/libsmtplib.tex +295 −0
  539. sys/src/cmd/python/Doc/lib/libsndhdr.tex +41 −0
  540. sys/src/cmd/python/Doc/lib/libsocket.tex +910 −0
  541. sys/src/cmd/python/Doc/lib/libsocksvr.tex +293 −0
  542. sys/src/cmd/python/Doc/lib/libsomeos.tex +10 −0
  543. sys/src/cmd/python/Doc/lib/libspwd.tex +48 −0
  544. sys/src/cmd/python/Doc/lib/libsqlite3.tex +642 −0
  545. sys/src/cmd/python/Doc/lib/libstat.tex +157 −0
  546. sys/src/cmd/python/Doc/lib/libstatvfs.tex +55 −0
  547. sys/src/cmd/python/Doc/lib/libstdtypes.tex +2095 −0
  548. sys/src/cmd/python/Doc/lib/libstdwin.tex +832 −0
  549. sys/src/cmd/python/Doc/lib/libstring.tex +451 −0
  550. sys/src/cmd/python/Doc/lib/libstringio.tex +121 −0
  551. sys/src/cmd/python/Doc/lib/libstringprep.tex +136 −0
  552. sys/src/cmd/python/Doc/lib/libstrings.tex +10 −0
  553. sys/src/cmd/python/Doc/lib/libstruct.tex +256 −0
  554. sys/src/cmd/python/Doc/lib/libsubprocess.tex +402 −0
  555. sys/src/cmd/python/Doc/lib/libsun.tex +5 −0
  556. sys/src/cmd/python/Doc/lib/libsunau.tex +218 −0
  557. sys/src/cmd/python/Doc/lib/libsunaudio.tex +146 −0
  558. sys/src/cmd/python/Doc/lib/libsymbol.tex +30 −0
  559. sys/src/cmd/python/Doc/lib/libsys.tex +617 −0
  560. sys/src/cmd/python/Doc/lib/libsyslog.tex +76 −0
  561. sys/src/cmd/python/Doc/lib/libtabnanny.tex +62 −0
  562. sys/src/cmd/python/Doc/lib/libtarfile.tex +497 −0
  563. sys/src/cmd/python/Doc/lib/libtelnetlib.tex +215 −0
  564. sys/src/cmd/python/Doc/lib/libtempfile.tex +194 −0
  565. sys/src/cmd/python/Doc/lib/libtermios.tex +106 −0
  566. sys/src/cmd/python/Doc/lib/libtest.tex +278 −0
  567. sys/src/cmd/python/Doc/lib/libtextwrap.tex +181 −0
  568. sys/src/cmd/python/Doc/lib/libthread.tex +173 −0
  569. sys/src/cmd/python/Doc/lib/libthreading.tex +716 −0
  570. sys/src/cmd/python/Doc/lib/libtime.tex +461 −0
  571. sys/src/cmd/python/Doc/lib/libtimeit.tex +224 −0
  572. sys/src/cmd/python/Doc/lib/libtoken.tex +44 −0
  573. sys/src/cmd/python/Doc/lib/libtokenize.tex +119 −0
  574. sys/src/cmd/python/Doc/lib/libtrace.tex +125 −0
  575. sys/src/cmd/python/Doc/lib/libtraceback.tex +157 −0
  576. sys/src/cmd/python/Doc/lib/libtty.tex +34 −0
  577. sys/src/cmd/python/Doc/lib/libturtle.tex +268 −0
  578. sys/src/cmd/python/Doc/lib/libtypes.tex +215 −0
  579. sys/src/cmd/python/Doc/lib/libundoc.tex +113 −0
  580. sys/src/cmd/python/Doc/lib/libunicodedata.tex +160 −0
  581. sys/src/cmd/python/Doc/lib/libunittest.tex +974 −0
  582. sys/src/cmd/python/Doc/lib/libunix.tex +8 −0
  583. sys/src/cmd/python/Doc/lib/liburllib.tex +497 −0
  584. sys/src/cmd/python/Doc/lib/liburllib2.tex +872 −0
  585. sys/src/cmd/python/Doc/lib/liburlparse.tex +253 −0
  586. sys/src/cmd/python/Doc/lib/libuser.tex +71 −0
  587. sys/src/cmd/python/Doc/lib/libuserdict.tex +181 −0
  588. sys/src/cmd/python/Doc/lib/libuu.tex +58 −0
  589. sys/src/cmd/python/Doc/lib/libuuid.tex +233 −0
  590. sys/src/cmd/python/Doc/lib/libwarnings.tex +253 −0
  591. sys/src/cmd/python/Doc/lib/libwave.tex +169 −0
  592. sys/src/cmd/python/Doc/lib/libweakref.tex +336 −0
  593. sys/src/cmd/python/Doc/lib/libwebbrowser.tex +173 −0
  594. sys/src/cmd/python/Doc/lib/libwhichdb.tex +20 −0
  595. sys/src/cmd/python/Doc/lib/libwinreg.tex +414 −0
  596. sys/src/cmd/python/Doc/lib/libwinsound.tex +142 −0
  597. sys/src/cmd/python/Doc/lib/libwsgiref.tex +782 −0
  598. sys/src/cmd/python/Doc/lib/libxdrlib.tex +251 −0
  599. sys/src/cmd/python/Doc/lib/libxmllib.tex +287 −0
  600. sys/src/cmd/python/Doc/lib/libxmlrpclib.tex +383 −0
  601. sys/src/cmd/python/Doc/lib/libzipfile.tex +309 −0
  602. sys/src/cmd/python/Doc/lib/libzipimport.tex +133 −0
  603. sys/src/cmd/python/Doc/lib/libzlib.tex +197 −0
  604. sys/src/cmd/python/Doc/lib/markup.tex +29 −0
  605. sys/src/cmd/python/Doc/lib/mimelib.tex +65 −0
  606. sys/src/cmd/python/Doc/lib/minidom-example.py +64 −0
  607. sys/src/cmd/python/Doc/lib/modules.tex +9 −0
  608. sys/src/cmd/python/Doc/lib/netdata.tex +6 −0
  609. sys/src/cmd/python/Doc/lib/numeric.tex +13 −0
  610. sys/src/cmd/python/Doc/lib/persistence.tex +15 −0
  611. sys/src/cmd/python/Doc/lib/required_1.py +20 −0
  612. sys/src/cmd/python/Doc/lib/required_2.py +41 −0
  613. sys/src/cmd/python/Doc/lib/sqlite3/adapter_datetime.py +14 −0
  614. sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_1.py +16 −0
  615. sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_2.py +17 −0
  616. sys/src/cmd/python/Doc/lib/sqlite3/collation_reverse.py +15 −0
  617. sys/src/cmd/python/Doc/lib/sqlite3/complete_statement.py +30 −0
  618. sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py +3 −0
  619. sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py +3 −0
  620. sys/src/cmd/python/Doc/lib/sqlite3/converter_point.py +47 −0
  621. sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py +15 −0
  622. sys/src/cmd/python/Doc/lib/sqlite3/createdb.py +28 −0
  623. sys/src/cmd/python/Doc/lib/sqlite3/execsql_fetchonerow.py +17 −0
  624. sys/src/cmd/python/Doc/lib/sqlite3/execsql_printall_1.py +13 −0
  625. sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py +11 −0
  626. sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py +12 −0
  627. sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py +12 −0
  628. sys/src/cmd/python/Doc/lib/sqlite3/executemany_1.py +24 −0
  629. sys/src/cmd/python/Doc/lib/sqlite3/executemany_2.py +15 −0
  630. sys/src/cmd/python/Doc/lib/sqlite3/executescript.py +24 −0
  631. sys/src/cmd/python/Doc/lib/sqlite3/insert_more_people.py +16 −0
  632. sys/src/cmd/python/Doc/lib/sqlite3/md5func.py +11 −0
  633. sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py +20 −0
  634. sys/src/cmd/python/Doc/lib/sqlite3/parse_colnames.py +8 −0
  635. sys/src/cmd/python/Doc/lib/sqlite3/pysqlite_datetime.py +20 −0
  636. sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py +13 −0
  637. sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py +12 −0
  638. sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py +6 −0
  639. sys/src/cmd/python/Doc/lib/sqlite3/shortcut_methods.py +21 −0
  640. sys/src/cmd/python/Doc/lib/sqlite3/simple_tableprinter.py +26 −0
  641. sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py +42 −0
  642. sys/src/cmd/python/Doc/lib/tkinter.tex +1873 −0
  643. sys/src/cmd/python/Doc/lib/tzinfo-examples.py +139 −0
  644. sys/src/cmd/python/Doc/lib/windows.tex +8 −0
  645. sys/src/cmd/python/Doc/lib/xmldom.tex +928 −0
  646. sys/src/cmd/python/Doc/lib/xmldomminidom.tex +285 −0
  647. sys/src/cmd/python/Doc/lib/xmldompulldom.tex +61 −0
  648. sys/src/cmd/python/Doc/lib/xmletree.tex +27 −0
  649. sys/src/cmd/python/Doc/lib/xmlsax.tex +143 −0
  650. sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex +381 −0
  651. sys/src/cmd/python/Doc/lib/xmlsaxreader.tex +351 −0
  652. sys/src/cmd/python/Doc/lib/xmlsaxutils.tex +81 −0
  653. sys/src/cmd/python/Doc/mac/libaepack.tex +82 −0
  654. sys/src/cmd/python/Doc/mac/libaetools.tex +83 −0
  655. sys/src/cmd/python/Doc/mac/libaetypes.tex +135 −0
  656. sys/src/cmd/python/Doc/mac/libautogil.tex +26 −0
  657. sys/src/cmd/python/Doc/mac/libcolorpicker.tex +23 −0
  658. sys/src/cmd/python/Doc/mac/libframework.tex +314 −0
  659. sys/src/cmd/python/Doc/mac/libgensuitemodule.tex +64 −0
  660. sys/src/cmd/python/Doc/mac/libmac.tex +29 −0
  661. sys/src/cmd/python/Doc/mac/libmacfs.tex +241 −0
  662. sys/src/cmd/python/Doc/mac/libmacic.tex +123 −0
  663. sys/src/cmd/python/Doc/mac/libmacos.tex +90 −0
  664. sys/src/cmd/python/Doc/mac/libmacostools.tex +105 −0
  665. sys/src/cmd/python/Doc/mac/libmacui.tex +266 −0
  666. sys/src/cmd/python/Doc/mac/libminiae.tex +65 −0
  667. sys/src/cmd/python/Doc/mac/libscrap.tex +42 −0
  668. sys/src/cmd/python/Doc/mac/mac.tex +89 −0
  669. sys/src/cmd/python/Doc/mac/scripting.tex +101 −0
  670. sys/src/cmd/python/Doc/mac/toolbox.tex +173 −0
  671. sys/src/cmd/python/Doc/mac/undoc.tex +97 −0
  672. sys/src/cmd/python/Doc/mac/using.tex +218 −0
  673. sys/src/cmd/python/Doc/paper-a4/pypaper.sty +17 −0
  674. sys/src/cmd/python/Doc/perl/SynopsisTable.pm +95 −0
  675. sys/src/cmd/python/Doc/perl/distutils.perl +21 −0
  676. sys/src/cmd/python/Doc/perl/howto.perl +12 −0
  677. sys/src/cmd/python/Doc/perl/isilo.perl +12 −0
  678. sys/src/cmd/python/Doc/perl/l2hinit.perl +801 −0
  679. sys/src/cmd/python/Doc/perl/ltxmarkup.perl +67 −0
  680. sys/src/cmd/python/Doc/perl/manual.perl +15 −0
  681. sys/src/cmd/python/Doc/perl/python.perl +2172 −0
  682. sys/src/cmd/python/Doc/python-docs.txt +183 −0
  683. sys/src/cmd/python/Doc/ref/ref.tex +68 −0
  684. sys/src/cmd/python/Doc/ref/ref1.tex +136 −0
  685. sys/src/cmd/python/Doc/ref/ref2.tex +731 −0
  686. sys/src/cmd/python/Doc/ref/ref3.tex +2225 −0
  687. sys/src/cmd/python/Doc/ref/ref4.tex +219 −0
  688. sys/src/cmd/python/Doc/ref/ref5.tex +1325 −0
  689. sys/src/cmd/python/Doc/ref/ref6.tex +928 −0
  690. sys/src/cmd/python/Doc/ref/ref7.tex +544 −0
  691. sys/src/cmd/python/Doc/ref/ref8.tex +112 −0
  692. sys/src/cmd/python/Doc/ref/reswords.py +23 −0
  693. sys/src/cmd/python/Doc/templates/howto.tex +112 −0
  694. sys/src/cmd/python/Doc/templates/manual.tex +89 −0
  695. sys/src/cmd/python/Doc/templates/module.tex +170 −0
  696. sys/src/cmd/python/Doc/templates/whatsnewXY.tex +149 −0
  697. sys/src/cmd/python/Doc/tests/math.tex +16 −0
  698. sys/src/cmd/python/Doc/texinputs/distutils.sty +33 −0
  699. sys/src/cmd/python/Doc/texinputs/fancyhdr.sty +329 −0
  700. sys/src/cmd/python/Doc/texinputs/fncychap.sty +433 −0
  701. sys/src/cmd/python/Doc/texinputs/howto.cls +109 −0
  702. sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty +40 −0
  703. sys/src/cmd/python/Doc/texinputs/manual.cls +155 −0
  704. sys/src/cmd/python/Doc/texinputs/pypaper.sty +18 −0
  705. sys/src/cmd/python/Doc/texinputs/python.ist +11 −0
  706. sys/src/cmd/python/Doc/texinputs/python.sty +1327 −0
  707. sys/src/cmd/python/Doc/texinputs/underscore.sty +232 −0
  708. sys/src/cmd/python/Doc/tools/anno-api.py +71 −0
  709. sys/src/cmd/python/Doc/tools/buildindex.py +388 −0
  710. sys/src/cmd/python/Doc/tools/checkargs.pm +112 −0
  711. sys/src/cmd/python/Doc/tools/cklatex +26 −0
  712. sys/src/cmd/python/Doc/tools/cmpcsyms +157 −0
  713. sys/src/cmd/python/Doc/tools/custlib.py +78 −0
  714. sys/src/cmd/python/Doc/tools/findcsyms +136 −0
  715. sys/src/cmd/python/Doc/tools/findmodrefs +63 −0
  716. sys/src/cmd/python/Doc/tools/findsyms +128 −0
  717. sys/src/cmd/python/Doc/tools/fix_hack +2 −0
  718. sys/src/cmd/python/Doc/tools/fix_libaux.sed +3 −0
  719. sys/src/cmd/python/Doc/tools/fixinfo.el +15 −0
  720. sys/src/cmd/python/Doc/tools/getpagecounts +97 −0
  721. sys/src/cmd/python/Doc/tools/getversioninfo +71 −0
  722. sys/src/cmd/python/Doc/tools/html2texi.pl +1750 −0
  723. sys/src/cmd/python/Doc/tools/indfix.py +100 −0
  724. sys/src/cmd/python/Doc/tools/keywords.py +19 −0
  725. sys/src/cmd/python/Doc/tools/listmodules +183 −0
  726. sys/src/cmd/python/Doc/tools/listmodules.py +126 −0
  727. sys/src/cmd/python/Doc/tools/makesec.sh +129 −0
  728. sys/src/cmd/python/Doc/tools/mkackshtml +66 −0
  729. sys/src/cmd/python/Doc/tools/mkhowto +659 −0
  730. sys/src/cmd/python/Doc/tools/mkinfo +65 −0
  731. sys/src/cmd/python/Doc/tools/mkmodindex +158 −0
  732. sys/src/cmd/python/Doc/tools/mkpkglist +85 −0
  733. sys/src/cmd/python/Doc/tools/mksourcepkg +164 −0
  734. sys/src/cmd/python/Doc/tools/node2label.pl +71 −0
  735. sys/src/cmd/python/Doc/tools/prechm.py +519 −0
  736. sys/src/cmd/python/Doc/tools/push-docs.sh +138 −0
  737. sys/src/cmd/python/Doc/tools/py2texi.el +970 −0
  738. sys/src/cmd/python/Doc/tools/refcounts.py +98 −0
  739. sys/src/cmd/python/Doc/tools/rewrite.py +54 −0
  740. sys/src/cmd/python/Doc/tools/sgmlconv/Makefile +67 −0
  741. sys/src/cmd/python/Doc/tools/sgmlconv/README +58 −0
  742. sys/src/cmd/python/Doc/tools/sgmlconv/conversion.xml +914 −0
  743. sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py +1073 −0
  744. sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py +264 −0
  745. sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py +312 −0
  746. sys/src/cmd/python/Doc/tools/sgmlconv/latex2esis.py +565 −0
  747. sys/src/cmd/python/Doc/tools/sgmlconv/make.rules +48 −0
  748. sys/src/cmd/python/Doc/tools/support.py +202 −0
  749. sys/src/cmd/python/Doc/tools/toc2bkm.py +160 −0
  750. sys/src/cmd/python/Doc/tools/undoc_symbols.py +94 −0
  751. sys/src/cmd/python/Doc/tools/update-docs.sh +31 −0
  752. sys/src/cmd/python/Doc/tools/whichlibs +2 −0
  753. sys/src/cmd/python/Doc/tut/glossary.tex +352 −0
  754. sys/src/cmd/python/Doc/tut/tut.tex +5907 −0
  755. sys/src/cmd/python/Doc/whatsnew/Makefile +3 −0
  756. sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex +1337 −0
  757. sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex +868 −0
  758. sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex +1466 −0
  759. sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex +2380 −0
  760. sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex +1757 −0
  761. sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex +2530 −0
  762. sys/src/cmd/python/Extra/dummy.c +6 −0
  763. sys/src/cmd/python/Extra/mercurial/base85.c +155 −0
  764. sys/src/cmd/python/Extra/mercurial/bdiff.c +401 −0
  765. sys/src/cmd/python/Extra/mercurial/diffhelpers.c +156 −0
  766. sys/src/cmd/python/Extra/mercurial/mpatch.c +444 −0
  767. sys/src/cmd/python/Extra/mercurial/osutil.c +534 −0
  768. sys/src/cmd/python/Extra/mercurial/parsers.c +435 −0
  769. sys/src/cmd/python/Extra/mkfile +16 −0
  770. sys/src/cmd/python/Grammar/Grammar +148 −0
  771. sys/src/cmd/python/Include/Python-ast.h +501 −0
  772. sys/src/cmd/python/Include/Python.h +173 −0
  773. sys/src/cmd/python/Include/abstract.h +1276 −0
  774. sys/src/cmd/python/Include/asdl.h +45 −0
  775. sys/src/cmd/python/Include/ast.h +13 −0
  776. sys/src/cmd/python/Include/bitset.h +32 −0
  777. sys/src/cmd/python/Include/boolobject.h +36 −0
  778. sys/src/cmd/python/Include/bufferobject.h +33 −0
  779. sys/src/cmd/python/Include/cStringIO.h +70 −0
  780. sys/src/cmd/python/Include/cellobject.h +28 −0
  781. sys/src/cmd/python/Include/ceval.h +157 −0
  782. sys/src/cmd/python/Include/classobject.h +81 −0
  783. sys/src/cmd/python/Include/cobject.h +54 −0
  784. sys/src/cmd/python/Include/code.h +94 −0
  785. sys/src/cmd/python/Include/codecs.h +167 −0
  786. sys/src/cmd/python/Include/compile.h +39 −0
  787. sys/src/cmd/python/Include/complexobject.h +58 −0
  788. sys/src/cmd/python/Include/datetime.h +245 −0
  789. sys/src/cmd/python/Include/descrobject.h +91 −0
  790. sys/src/cmd/python/Include/dictobject.h +141 −0
  791. sys/src/cmd/python/Include/enumobject.h +17 −0
  792. sys/src/cmd/python/Include/errcode.h +36 −0
  793. sys/src/cmd/python/Include/eval.h +25 −0
  794. sys/src/cmd/python/Include/fileobject.h +63 −0
  795. sys/src/cmd/python/Include/floatobject.h +100 −0
  796. sys/src/cmd/python/Include/frameobject.h +81 −0
  797. sys/src/cmd/python/Include/funcobject.h +76 −0
  798. sys/src/cmd/python/Include/genobject.h +37 −0
  799. sys/src/cmd/python/Include/graminit.h +84 −0
  800. sys/src/cmd/python/Include/grammar.h +93 −0
  801. sys/src/cmd/python/Include/import.h +64 −0
  802. sys/src/cmd/python/Include/intobject.h +64 −0
  803. sys/src/cmd/python/Include/intrcheck.h +15 −0
  804. sys/src/cmd/python/Include/iterobject.h +23 −0
  805. sys/src/cmd/python/Include/listobject.h +67 −0
  806. sys/src/cmd/python/Include/longintrepr.h +63 −0
  807. sys/src/cmd/python/Include/longobject.h +114 −0
  808. sys/src/cmd/python/Include/marshal.h +25 −0
  809. sys/src/cmd/python/Include/metagrammar.h +18 −0
  810. sys/src/cmd/python/Include/methodobject.h +91 −0
  811. sys/src/cmd/python/Include/modsupport.h +133 −0
  812. sys/src/cmd/python/Include/moduleobject.h +24 −0
  813. sys/src/cmd/python/Include/node.h +40 −0
  814. sys/src/cmd/python/Include/object.h +868 −0
  815. sys/src/cmd/python/Include/objimpl.h +336 −0
  816. sys/src/cmd/python/Include/opcode.h +152 −0
  817. sys/src/cmd/python/Include/osdefs.h +55 −0
  818. sys/src/cmd/python/Include/parsetok.h +50 −0
  819. sys/src/cmd/python/Include/patchlevel.h +40 −0
  820. sys/src/cmd/python/Include/pgen.h +18 −0
  821. sys/src/cmd/python/Include/pgenheaders.h +42 −0
  822. sys/src/cmd/python/Include/py_curses.h +176 −0
  823. sys/src/cmd/python/Include/pyarena.h +62 −0
  824. sys/src/cmd/python/Include/pydebug.h +34 −0
  825. sys/src/cmd/python/Include/pyerrors.h +334 −0
  826. sys/src/cmd/python/Include/pyexpat.h +47 −0
  827. sys/src/cmd/python/Include/pyfpe.h +176 −0
  828. sys/src/cmd/python/Include/pygetopt.h +17 −0
  829. sys/src/cmd/python/Include/pymactoolbox.h +189 −0
  830. sys/src/cmd/python/Include/pymem.h +105 −0
  831. sys/src/cmd/python/Include/pyport.h +771 −0
  832. sys/src/cmd/python/Include/pystate.h +195 −0
  833. sys/src/cmd/python/Include/pystrtod.h +18 −0
  834. sys/src/cmd/python/Include/pythonrun.h +171 −0
  835. sys/src/cmd/python/Include/pythread.h +47 −0
  836. sys/src/cmd/python/Include/rangeobject.h +28 −0
  837. sys/src/cmd/python/Include/setobject.h +93 −0
  838. sys/src/cmd/python/Include/sliceobject.h +43 −0
  839. sys/src/cmd/python/Include/stringobject.h +183 −0
  840. sys/src/cmd/python/Include/structmember.h +93 −0
  841. sys/src/cmd/python/Include/structseq.h +41 −0
  842. sys/src/cmd/python/Include/symtable.h +103 −0
  843. sys/src/cmd/python/Include/sysmodule.h +30 −0
  844. sys/src/cmd/python/Include/timefuncs.h +23 −0
  845. sys/src/cmd/python/Include/token.h +83 −0
  846. sys/src/cmd/python/Include/traceback.h +30 −0
  847. sys/src/cmd/python/Include/tupleobject.h +57 −0
  848. sys/src/cmd/python/Include/ucnhash.h +31 −0
  849. sys/src/cmd/python/Include/unicodeobject.h +1265 −0
  850. sys/src/cmd/python/Include/weakrefobject.h +75 −0
  851. sys/src/cmd/python/LICENSE +270 −0
  852. sys/src/cmd/python/Misc/ACKS +698 −0
  853. sys/src/cmd/python/Misc/AIX-NOTES +155 −0
  854. sys/src/cmd/python/Misc/BeOS-NOTES +43 −0
  855. sys/src/cmd/python/Misc/BeOS-setup.py +574 −0
  856. sys/src/cmd/python/Misc/NEWS +2782 −0
  857. sys/src/cmd/python/Misc/NEWS.help +73 −0
  858. sys/src/cmd/python/Misc/PURIFY.README +97 −0
  859. sys/src/cmd/python/Misc/Porting +42 −0
  860. sys/src/cmd/python/Misc/README +33 −0
  861. sys/src/cmd/python/Misc/README.OpenBSD +38 −0
  862. sys/src/cmd/python/Misc/README.coverity +22 −0
  863. sys/src/cmd/python/Misc/README.klocwork +30 −0
  864. sys/src/cmd/python/Misc/README.valgrind +97 −0
  865. sys/src/cmd/python/Misc/RFD +114 −0
  866. sys/src/cmd/python/Misc/RPM/README +16 −0
  867. sys/src/cmd/python/Misc/RPM/python-2.5.spec +395 −0
  868. sys/src/cmd/python/Misc/SpecialBuilds.txt +261 −0
  869. sys/src/cmd/python/Misc/Vim/python.vim +147 −0
  870. sys/src/cmd/python/Misc/Vim/syntax_test.py +63 −0
  871. sys/src/cmd/python/Misc/Vim/vim_syntax.py +226 −0
  872. sys/src/cmd/python/Misc/Vim/vimrc +95 −0
  873. sys/src/cmd/python/Misc/build.sh +227 −0
  874. sys/src/cmd/python/Misc/cheatsheet +2279 −0
  875. sys/src/cmd/python/Misc/developers.txt +141 −0
  876. sys/src/cmd/python/Misc/find_recursionlimit.py +87 −0
  877. sys/src/cmd/python/Misc/gdbinit +140 −0
  878. sys/src/cmd/python/Misc/indent.pro +15 −0
  879. sys/src/cmd/python/Misc/pymemcompat.h +85 −0
  880. sys/src/cmd/python/Misc/python-config.in +53 −0
  881. sys/src/cmd/python/Misc/python-mode.el +3768 −0
  882. sys/src/cmd/python/Misc/python.man +397 −0
  883. sys/src/cmd/python/Misc/setuid-prog.c +176 −0
  884. sys/src/cmd/python/Misc/valgrind-python.supp +349 −0
  885. sys/src/cmd/python/Misc/vgrindefs +10 −0
  886. sys/src/cmd/python/Modules/Setup +488 −0
  887. sys/src/cmd/python/Modules/Setup.config +13 −0
  888. sys/src/cmd/python/Modules/Setup.config.in +13 −0
  889. sys/src/cmd/python/Modules/Setup.dist +487 −0
  890. sys/src/cmd/python/Modules/Setup.local +1 −0
  891. sys/src/cmd/python/Modules/_bisectmodule.c +235 −0
  892. sys/src/cmd/python/Modules/_bsddb.c +6047 −0
  893. sys/src/cmd/python/Modules/_codecsmodule.c +934 −0
  894. sys/src/cmd/python/Modules/_csv.c +1604 −0
sys/src/cmd/python/Demo/README+61−0
@@ -0,0 +1,61 @@
1+This directory contains various demonstrations of what you can do with
2+Python. They were all written by me except where explicitly stated
3+otherwise -- in general, demos contributed by others ends up in the
4+../Contrib directory, unless I think they're of utmost general
5+importance (like Matt Conway's Tk demos).
6+
7+A fair number of utilities that are useful when while developing
8+Python code can be found in the ../Tools directory -- some of these
9+can also be considered good examples of how to write Python code.
10+
11+Finally, in order to save disk space and net bandwidth, not all
12+subdirectories listed here are distributed. They are listed just
13+in case I change my mind about them.
14+
15+
16+cgi CGI examples (see also ../Tools/faqwiz/.)
17+
18+classes Some examples of how to use classes.
19+
20+comparisons A set of responses to a really old language-comparison
21+ challenge.
22+
23+curses A set of curses demos.
24+
25+embed An example of embedding Python in another application
26+ (see also pysvr).
27+
28+imputil Demonstration subclasses of imputil.Importer.
29+
30+md5test Test program for the optional md5 module.
31+
32+metaclasses The code from the 1.5 metaclasses paper on the web.
33+
34+parser Example using the parser module.
35+
36+pdist Old, unfinished code messing with CVS, RCS and remote
37+ files.
38+
39+pysvr An example of embedding Python in a threaded
40+ application.
41+
42+rpc A set of classes for building clients and servers for
43+ Sun RPC.
44+
45+scripts Some useful Python scripts that I put in my bin
46+ directory. No optional built-in modules needed.
47+
48+sockets Examples for the new built-in module 'socket'.
49+
50+threads Demos that use the 'thread' module. (Currently these
51+ only run on SGIs, but this may change in the future.)
52+
53+tix Demos using the Tix widget set addition to Tkinter.
54+
55+tkinter Demos using the Tk interface (including Matt Conway's
56+ excellent set of demos).
57+
58+xml Some XML demos.
59+
60+zlib Some demos for the zlib module (see also the standard
61+ library module gzip.py).
sys/src/cmd/python/Demo/cgi/README+11−0
@@ -0,0 +1,11 @@
1+CGI Examples
2+------------
3+
4+Here are some example CGI programs. For a larger example, see
5+../../Tools/faqwiz/.
6+
7+cgi0.sh -- A shell script to test your server is configured for CGI
8+cgi1.py -- A Python script to test your server is configured for CGI
9+cgi2.py -- A Python script showing how to parse a form
10+cgi3.py -- A Python script for driving an arbitrary CGI application
11+wiki.py -- Sample CGI application: a minimal Wiki implementation
sys/src/cmd/python/Demo/cgi/cgi0.sh+8−0
@@ -0,0 +1,8 @@
1+#! /bin/sh
2+
3+# If you can't get this to work, your web server isn't set up right
4+
5+echo Content-type: text/plain
6+echo
7+echo Hello world
8+echo This is cgi0.sh
sys/src/cmd/python/Demo/cgi/cgi1.py+14−0
@@ -0,0 +1,14 @@
1+#!/usr/local/bin/python
2+
3+"""CGI test 1 - check server setup."""
4+
5+# Until you get this to work, your web server isn't set up right or
6+# your Python isn't set up right.
7+
8+# If cgi0.sh works but cgi1.py doesn't, check the #! line and the file
9+# permissions. The docs for the cgi.py module have debugging tips.
10+
11+print "Content-type: text/html"
12+print
13+print "<h1>Hello world</h1>"
14+print "<p>This is cgi1.py"
sys/src/cmd/python/Demo/cgi/cgi2.py+22−0
@@ -0,0 +1,22 @@
1+#!/usr/local/bin/python
2+
3+"""CGI test 2 - basic use of cgi module."""
4+
5+import cgitb; cgitb.enable()
6+
7+import cgi
8+
9+def main():
10+ form = cgi.FieldStorage()
11+ print "Content-type: text/html"
12+ print
13+ if not form:
14+ print "<h1>No Form Keys</h1>"
15+ else:
16+ print "<h1>Form Keys</h1>"
17+ for key in form.keys():
18+ value = form[key].value
19+ print "<p>", cgi.escape(key), ":", cgi.escape(value)
20+
21+if __name__ == "__main__":
22+ main()
sys/src/cmd/python/Demo/cgi/cgi3.py+10−0
@@ -0,0 +1,10 @@
1+#!/usr/local/bin/python
2+
3+"""CGI test 3 (persistent data)."""
4+
5+import cgitb; cgitb.enable()
6+
7+from wiki import main
8+
9+if __name__ == "__main__":
10+ main()
sys/src/cmd/python/Demo/cgi/wiki.py+123−0
@@ -0,0 +1,123 @@
1+"""Wiki main program. Imported and run by cgi3.py."""
2+
3+import os, re, cgi, sys, tempfile
4+escape = cgi.escape
5+
6+def main():
7+ form = cgi.FieldStorage()
8+ print "Content-type: text/html"
9+ print
10+ cmd = form.getvalue("cmd", "view")
11+ page = form.getvalue("page", "FrontPage")
12+ wiki = WikiPage(page)
13+ method = getattr(wiki, 'cmd_' + cmd, None) or wiki.cmd_view
14+ method(form)
15+
16+class WikiPage:
17+
18+ homedir = tempfile.gettempdir()
19+ scripturl = os.path.basename(sys.argv[0])
20+
21+ def __init__(self, name):
22+ if not self.iswikiword(name):
23+ raise ValueError, "page name is not a wiki word"
24+ self.name = name
25+ self.load()
26+
27+ def cmd_view(self, form):
28+ print "<h1>", escape(self.splitwikiword(self.name)), "</h1>"
29+ print "<p>"
30+ for line in self.data.splitlines():
31+ line = line.rstrip()
32+ if not line:
33+ print "<p>"
34+ else:
35+ print self.formatline(line)
36+ print "<hr>"
37+ print "<p>", self.mklink("edit", self.name, "Edit this page") + ";"
38+ print self.mklink("view", "FrontPage", "go to front page") + "."
39+
40+ def formatline(self, line):
41+ words = []
42+ for word in re.split('(\W+)', line):
43+ if self.iswikiword(word):
44+ if os.path.isfile(self.mkfile(word)):
45+ word = self.mklink("view", word, word)
46+ else:
47+ word = self.mklink("new", word, word + "*")
48+ else:
49+ word = escape(word)
50+ words.append(word)
51+ return "".join(words)
52+
53+ def cmd_edit(self, form, label="Change"):
54+ print "<h1>", label, self.name, "</h1>"
55+ print '<form method="POST" action="%s">' % self.scripturl
56+ s = '<textarea cols="70" rows="20" name="text">%s</textarea>'
57+ print s % self.data
58+ print '<input type="hidden" name="cmd" value="create">'
59+ print '<input type="hidden" name="page" value="%s">' % self.name
60+ print '<br>'
61+ print '<input type="submit" value="%s Page">' % label
62+ print "</form>"
63+
64+ def cmd_create(self, form):
65+ self.data = form.getvalue("text", "").strip()
66+ error = self.store()
67+ if error:
68+ print "<h1>I'm sorry. That didn't work</h1>"
69+ print "<p>An error occurred while attempting to write the file:"
70+ print "<p>", escape(error)
71+ else:
72+ # Use a redirect directive, to avoid "reload page" problems
73+ print "<head>"
74+ s = '<meta http-equiv="refresh" content="1; URL=%s">'
75+ print s % (self.scripturl + "?cmd=view&page=" + self.name)
76+ print "<head>"
77+ print "<h1>OK</h1>"
78+ print "<p>If nothing happens, please click here:",
79+ print self.mklink("view", self.name, self.name)
80+
81+ def cmd_new(self, form):
82+ self.cmd_edit(form, label="Create")
83+
84+ def iswikiword(self, word):
85+ return re.match("[A-Z][a-z]+([A-Z][a-z]*)+", word)
86+
87+ def splitwikiword(self, word):
88+ chars = []
89+ for c in word:
90+ if chars and c.isupper():
91+ chars.append(' ')
92+ chars.append(c)
93+ return "".join(chars)
94+
95+ def mkfile(self, name=None):
96+ if name is None:
97+ name = self.name
98+ return os.path.join(self.homedir, name + ".txt")
99+
100+ def mklink(self, cmd, page, text):
101+ link = self.scripturl + "?cmd=" + cmd + "&page=" + page
102+ return '<a href="%s">%s</a>' % (link, text)
103+
104+ def load(self):
105+ try:
106+ f = open(self.mkfile())
107+ data = f.read().strip()
108+ f.close()
109+ except IOError:
110+ data = ""
111+ self.data = data
112+
113+ def store(self):
114+ data = self.data
115+ try:
116+ f = open(self.mkfile(), "w")
117+ f.write(data)
118+ if data and not data.endswith('\n'):
119+ f.write('\n')
120+ f.close()
121+ return ""
122+ except IOError, err:
123+ return "IOError: %s" % str(err)
sys/src/cmd/python/Demo/classes/Complex.py+320−0
@@ -0,0 +1,320 @@
1+# Complex numbers
2+# ---------------
3+
4+# [Now that Python has a complex data type built-in, this is not very
5+# useful, but it's still a nice example class]
6+
7+# This module represents complex numbers as instances of the class Complex.
8+# A Complex instance z has two data attribues, z.re (the real part) and z.im
9+# (the imaginary part). In fact, z.re and z.im can have any value -- all
10+# arithmetic operators work regardless of the type of z.re and z.im (as long
11+# as they support numerical operations).
12+#
13+# The following functions exist (Complex is actually a class):
14+# Complex([re [,im]) -> creates a complex number from a real and an imaginary part
15+# IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
16+# ToComplex(z) -> a complex number equal to z; z itself if IsComplex(z) is true
17+# if z is a tuple(re, im) it will also be converted
18+# PolarToComplex([r [,phi [,fullcircle]]]) ->
19+# the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
20+# (r and phi default to 0)
21+# exp(z) -> returns the complex exponential of z. Equivalent to pow(math.e,z).
22+#
23+# Complex numbers have the following methods:
24+# z.abs() -> absolute value of z
25+# z.radius() == z.abs()
26+# z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
27+# z.phi([fullcircle]) == z.angle(fullcircle)
28+#
29+# These standard functions and unary operators accept complex arguments:
30+# abs(z)
31+# -z
32+# +z
33+# not z
34+# repr(z) == `z`
35+# str(z)
36+# hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
37+# the result equals hash(z.re)
38+# Note that hex(z) and oct(z) are not defined.
39+#
40+# These conversions accept complex arguments only if their imaginary part is zero:
41+# int(z)
42+# long(z)
43+# float(z)
44+#
45+# The following operators accept two complex numbers, or one complex number
46+# and one real number (int, long or float):
47+# z1 + z2
48+# z1 - z2
49+# z1 * z2
50+# z1 / z2
51+# pow(z1, z2)
52+# cmp(z1, z2)
53+# Note that z1 % z2 and divmod(z1, z2) are not defined,
54+# nor are shift and mask operations.
55+#
56+# The standard module math does not support complex numbers.
57+# The cmath modules should be used instead.
58+#
59+# Idea:
60+# add a class Polar(r, phi) and mixed-mode arithmetic which
61+# chooses the most appropriate type for the result:
62+# Complex for +,-,cmp
63+# Polar for *,/,pow
64+
65+import math
66+import sys
67+
68+twopi = math.pi*2.0
69+halfpi = math.pi/2.0
70+
71+def IsComplex(obj):
72+ return hasattr(obj, 're') and hasattr(obj, 'im')
73+
74+def ToComplex(obj):
75+ if IsComplex(obj):
76+ return obj
77+ elif isinstance(obj, tuple):
78+ return Complex(*obj)
79+ else:
80+ return Complex(obj)
81+
82+def PolarToComplex(r = 0, phi = 0, fullcircle = twopi):
83+ phi = phi * (twopi / fullcircle)
84+ return Complex(math.cos(phi)*r, math.sin(phi)*r)
85+
86+def Re(obj):
87+ if IsComplex(obj):
88+ return obj.re
89+ return obj
90+
91+def Im(obj):
92+ if IsComplex(obj):
93+ return obj.im
94+ return 0
95+
96+class Complex:
97+
98+ def __init__(self, re=0, im=0):
99+ _re = 0
100+ _im = 0
101+ if IsComplex(re):
102+ _re = re.re
103+ _im = re.im
104+ else:
105+ _re = re
106+ if IsComplex(im):
107+ _re = _re - im.im
108+ _im = _im + im.re
109+ else:
110+ _im = _im + im
111+ # this class is immutable, so setting self.re directly is
112+ # not possible.
113+ self.__dict__['re'] = _re
114+ self.__dict__['im'] = _im
115+
116+ def __setattr__(self, name, value):
117+ raise TypeError, 'Complex numbers are immutable'
118+
119+ def __hash__(self):
120+ if not self.im:
121+ return hash(self.re)
122+ return hash((self.re, self.im))
123+
124+ def __repr__(self):
125+ if not self.im:
126+ return 'Complex(%r)' % (self.re,)
127+ else:
128+ return 'Complex(%r, %r)' % (self.re, self.im)
129+
130+ def __str__(self):
131+ if not self.im:
132+ return repr(self.re)
133+ else:
134+ return 'Complex(%r, %r)' % (self.re, self.im)
135+
136+ def __neg__(self):
137+ return Complex(-self.re, -self.im)
138+
139+ def __pos__(self):
140+ return self
141+
142+ def __abs__(self):
143+ return math.hypot(self.re, self.im)
144+
145+ def __int__(self):
146+ if self.im:
147+ raise ValueError, "can't convert Complex with nonzero im to int"
148+ return int(self.re)
149+
150+ def __long__(self):
151+ if self.im:
152+ raise ValueError, "can't convert Complex with nonzero im to long"
153+ return long(self.re)
154+
155+ def __float__(self):
156+ if self.im:
157+ raise ValueError, "can't convert Complex with nonzero im to float"
158+ return float(self.re)
159+
160+ def __cmp__(self, other):
161+ other = ToComplex(other)
162+ return cmp((self.re, self.im), (other.re, other.im))
163+
164+ def __rcmp__(self, other):
165+ other = ToComplex(other)
166+ return cmp(other, self)
167+
168+ def __nonzero__(self):
169+ return not (self.re == self.im == 0)
170+
171+ abs = radius = __abs__
172+
173+ def angle(self, fullcircle = twopi):
174+ return (fullcircle/twopi) * ((halfpi - math.atan2(self.re, self.im)) % twopi)
175+
176+ phi = angle
177+
178+ def __add__(self, other):
179+ other = ToComplex(other)
180+ return Complex(self.re + other.re, self.im + other.im)
181+
182+ __radd__ = __add__
183+
184+ def __sub__(self, other):
185+ other = ToComplex(other)
186+ return Complex(self.re - other.re, self.im - other.im)
187+
188+ def __rsub__(self, other):
189+ other = ToComplex(other)
190+ return other - self
191+
192+ def __mul__(self, other):
193+ other = ToComplex(other)
194+ return Complex(self.re*other.re - self.im*other.im,
195+ self.re*other.im + self.im*other.re)
196+
197+ __rmul__ = __mul__
198+
199+ def __div__(self, other):
200+ other = ToComplex(other)
201+ d = float(other.re*other.re + other.im*other.im)
202+ if not d: raise ZeroDivisionError, 'Complex division'
203+ return Complex((self.re*other.re + self.im*other.im) / d,
204+ (self.im*other.re - self.re*other.im) / d)
205+
206+ def __rdiv__(self, other):
207+ other = ToComplex(other)
208+ return other / self
209+
210+ def __pow__(self, n, z=None):
211+ if z is not None:
212+ raise TypeError, 'Complex does not support ternary pow()'
213+ if IsComplex(n):
214+ if n.im:
215+ if self.im: raise TypeError, 'Complex to the Complex power'
216+ else: return exp(math.log(self.re)*n)
217+ n = n.re
218+ r = pow(self.abs(), n)
219+ phi = n*self.angle()
220+ return Complex(math.cos(phi)*r, math.sin(phi)*r)
221+
222+ def __rpow__(self, base):
223+ base = ToComplex(base)
224+ return pow(base, self)
225+
226+def exp(z):
227+ r = math.exp(z.re)
228+ return Complex(math.cos(z.im)*r,math.sin(z.im)*r)
229+
230+
231+def checkop(expr, a, b, value, fuzz = 1e-6):
232+ print ' ', a, 'and', b,
233+ try:
234+ result = eval(expr)
235+ except:
236+ result = sys.exc_type
237+ print '->', result
238+ if isinstance(result, str) or isinstance(value, str):
239+ ok = (result == value)
240+ else:
241+ ok = abs(result - value) <= fuzz
242+ if not ok:
243+ print '!!\t!!\t!! should be', value, 'diff', abs(result - value)
244+
245+def test():
246+ print 'test constructors'
247+ constructor_test = (
248+ # "expect" is an array [re,im] "got" the Complex.
249+ ( (0,0), Complex() ),
250+ ( (0,0), Complex() ),
251+ ( (1,0), Complex(1) ),
252+ ( (0,1), Complex(0,1) ),
253+ ( (1,2), Complex(Complex(1,2)) ),
254+ ( (1,3), Complex(Complex(1,2),1) ),
255+ ( (0,0), Complex(0,Complex(0,0)) ),
256+ ( (3,4), Complex(3,Complex(4)) ),
257+ ( (-1,3), Complex(1,Complex(3,2)) ),
258+ ( (-7,6), Complex(Complex(1,2),Complex(4,8)) ) )
259+ cnt = [0,0]
260+ for t in constructor_test:
261+ cnt[0] += 1
262+ if ((t[0][0]!=t[1].re)or(t[0][1]!=t[1].im)):
263+ print " expected", t[0], "got", t[1]
264+ cnt[1] += 1
265+ print " ", cnt[1], "of", cnt[0], "tests failed"
266+ # test operators
267+ testsuite = {
268+ 'a+b': [
269+ (1, 10, 11),
270+ (1, Complex(0,10), Complex(1,10)),
271+ (Complex(0,10), 1, Complex(1,10)),
272+ (Complex(0,10), Complex(1), Complex(1,10)),
273+ (Complex(1), Complex(0,10), Complex(1,10)),
274+ ],
275+ 'a-b': [
276+ (1, 10, -9),
277+ (1, Complex(0,10), Complex(1,-10)),
278+ (Complex(0,10), 1, Complex(-1,10)),
279+ (Complex(0,10), Complex(1), Complex(-1,10)),
280+ (Complex(1), Complex(0,10), Complex(1,-10)),
281+ ],
282+ 'a*b': [
283+ (1, 10, 10),
284+ (1, Complex(0,10), Complex(0, 10)),
285+ (Complex(0,10), 1, Complex(0,10)),
286+ (Complex(0,10), Complex(1), Complex(0,10)),
287+ (Complex(1), Complex(0,10), Complex(0,10)),
288+ ],
289+ 'a/b': [
290+ (1., 10, 0.1),
291+ (1, Complex(0,10), Complex(0, -0.1)),
292+ (Complex(0, 10), 1, Complex(0, 10)),
293+ (Complex(0, 10), Complex(1), Complex(0, 10)),
294+ (Complex(1), Complex(0,10), Complex(0, -0.1)),
295+ ],
296+ 'pow(a,b)': [
297+ (1, 10, 1),
298+ (1, Complex(0,10), 1),
299+ (Complex(0,10), 1, Complex(0,10)),
300+ (Complex(0,10), Complex(1), Complex(0,10)),
301+ (Complex(1), Complex(0,10), 1),
302+ (2, Complex(4,0), 16),
303+ ],
304+ 'cmp(a,b)': [
305+ (1, 10, -1),
306+ (1, Complex(0,10), 1),
307+ (Complex(0,10), 1, -1),
308+ (Complex(0,10), Complex(1), -1),
309+ (Complex(1), Complex(0,10), 1),
310+ ],
311+ }
312+ for expr in sorted(testsuite):
313+ print expr + ':'
314+ t = (expr,)
315+ for item in testsuite[expr]:
316+ checkop(*(t+item))
317+
318+
319+if __name__ == '__main__':
320+ test()
sys/src/cmd/python/Demo/classes/Dates.py+222−0
@@ -0,0 +1,222 @@
1+# Class Date supplies date objects that support date arithmetic.
2+#
3+# Date(month,day,year) returns a Date object. An instance prints as,
4+# e.g., 'Mon 16 Aug 1993'.
5+#
6+# Addition, subtraction, comparison operators, min, max, and sorting
7+# all work as expected for date objects: int+date or date+int returns
8+# the date `int' days from `date'; date+date raises an exception;
9+# date-int returns the date `int' days before `date'; date2-date1 returns
10+# an integer, the number of days from date1 to date2; int-date raises an
11+# exception; date1 < date2 is true iff date1 occurs before date2 (&
12+# similarly for other comparisons); min(date1,date2) is the earlier of
13+# the two dates and max(date1,date2) the later; and date objects can be
14+# used as dictionary keys.
15+#
16+# Date objects support one visible method, date.weekday(). This returns
17+# the day of the week the date falls on, as a string.
18+#
19+# Date objects also have 4 read-only data attributes:
20+# .month in 1..12
21+# .day in 1..31
22+# .year int or long int
23+# .ord the ordinal of the date relative to an arbitrary staring point
24+#
25+# The Dates module also supplies function today(), which returns the
26+# current date as a date object.
27+#
28+# Those entranced by calendar trivia will be disappointed, as no attempt
29+# has been made to accommodate the Julian (etc) system. On the other
30+# hand, at least this package knows that 2000 is a leap year but 2100
31+# isn't, and works fine for years with a hundred decimal digits <wink>.
32+
33+# Tim Peters tim@ksr.com
34+# not speaking for Kendall Square Research Corp
35+
36+# Adapted to Python 1.1 (where some hacks to overcome coercion are unnecessary)
37+# by Guido van Rossum
38+
39+# Note that as of Python 2.3, a datetime module is included in the stardard
40+# library.
41+
42+# vi:set tabsize=8:
43+
44+_MONTH_NAMES = [ 'January', 'February', 'March', 'April', 'May',
45+ 'June', 'July', 'August', 'September', 'October',
46+ 'November', 'December' ]
47+
48+_DAY_NAMES = [ 'Friday', 'Saturday', 'Sunday', 'Monday',
49+ 'Tuesday', 'Wednesday', 'Thursday' ]
50+
51+_DAYS_IN_MONTH = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
52+
53+_DAYS_BEFORE_MONTH = []
54+dbm = 0
55+for dim in _DAYS_IN_MONTH:
56+ _DAYS_BEFORE_MONTH.append(dbm)
57+ dbm = dbm + dim
58+del dbm, dim
59+
60+_INT_TYPES = type(1), type(1L)
61+
62+def _is_leap(year): # 1 if leap year, else 0
63+ if year % 4 != 0: return 0
64+ if year % 400 == 0: return 1
65+ return year % 100 != 0
66+
67+def _days_in_year(year): # number of days in year
68+ return 365 + _is_leap(year)
69+
70+def _days_before_year(year): # number of days before year
71+ return year*365L + (year+3)/4 - (year+99)/100 + (year+399)/400
72+
73+def _days_in_month(month, year): # number of days in month of year
74+ if month == 2 and _is_leap(year): return 29
75+ return _DAYS_IN_MONTH[month-1]
76+
77+def _days_before_month(month, year): # number of days in year before month
78+ return _DAYS_BEFORE_MONTH[month-1] + (month > 2 and _is_leap(year))
79+
80+def _date2num(date): # compute ordinal of date.month,day,year
81+ return _days_before_year(date.year) + \
82+ _days_before_month(date.month, date.year) + \
83+ date.day
84+
85+_DI400Y = _days_before_year(400) # number of days in 400 years
86+
87+def _num2date(n): # return date with ordinal n
88+ if type(n) not in _INT_TYPES:
89+ raise TypeError, 'argument must be integer: %r' % type(n)
90+
91+ ans = Date(1,1,1) # arguments irrelevant; just getting a Date obj
92+ del ans.ord, ans.month, ans.day, ans.year # un-initialize it
93+ ans.ord = n
94+
95+ n400 = (n-1)/_DI400Y # # of 400-year blocks preceding
96+ year, n = 400 * n400, n - _DI400Y * n400
97+ more = n / 365
98+ dby = _days_before_year(more)
99+ if dby >= n:
100+ more = more - 1
101+ dby = dby - _days_in_year(more)
102+ year, n = year + more, int(n - dby)
103+
104+ try: year = int(year) # chop to int, if it fits
105+ except (ValueError, OverflowError): pass
106+
107+ month = min(n/29 + 1, 12)
108+ dbm = _days_before_month(month, year)
109+ if dbm >= n:
110+ month = month - 1
111+ dbm = dbm - _days_in_month(month, year)
112+
113+ ans.month, ans.day, ans.year = month, n-dbm, year
114+ return ans
115+
116+def _num2day(n): # return weekday name of day with ordinal n
117+ return _DAY_NAMES[ int(n % 7) ]
118+
119+
120+class Date:
121+ def __init__(self, month, day, year):
122+ if not 1 <= month <= 12:
123+ raise ValueError, 'month must be in 1..12: %r' % (month,)
124+ dim = _days_in_month(month, year)
125+ if not 1 <= day <= dim:
126+ raise ValueError, 'day must be in 1..%r: %r' % (dim, day)
127+ self.month, self.day, self.year = month, day, year
128+ self.ord = _date2num(self)
129+
130+ # don't allow setting existing attributes
131+ def __setattr__(self, name, value):
132+ if self.__dict__.has_key(name):
133+ raise AttributeError, 'read-only attribute ' + name
134+ self.__dict__[name] = value
135+
136+ def __cmp__(self, other):
137+ return cmp(self.ord, other.ord)
138+
139+ # define a hash function so dates can be used as dictionary keys
140+ def __hash__(self):
141+ return hash(self.ord)
142+
143+ # print as, e.g., Mon 16 Aug 1993
144+ def __repr__(self):
145+ return '%.3s %2d %.3s %r' % (
146+ self.weekday(),
147+ self.day,
148+ _MONTH_NAMES[self.month-1],
149+ self.year)
150+
151+ # Python 1.1 coerces neither int+date nor date+int
152+ def __add__(self, n):
153+ if type(n) not in _INT_TYPES:
154+ raise TypeError, 'can\'t add %r to date' % type(n)
155+ return _num2date(self.ord + n)
156+ __radd__ = __add__ # handle int+date
157+
158+ # Python 1.1 coerces neither date-int nor date-date
159+ def __sub__(self, other):
160+ if type(other) in _INT_TYPES: # date-int
161+ return _num2date(self.ord - other)
162+ else:
163+ return self.ord - other.ord # date-date
164+
165+ # complain about int-date
166+ def __rsub__(self, other):
167+ raise TypeError, 'Can\'t subtract date from integer'
168+
169+ def weekday(self):
170+ return _num2day(self.ord)
171+
172+def today():
173+ import time
174+ local = time.localtime(time.time())
175+ return Date(local[1], local[2], local[0])
176+
177+DateTestError = 'DateTestError'
178+def test(firstyear, lastyear):
179+ a = Date(9,30,1913)
180+ b = Date(9,30,1914)
181+ if repr(a) != 'Tue 30 Sep 1913':
182+ raise DateTestError, '__repr__ failure'
183+ if (not a < b) or a == b or a > b or b != b:
184+ raise DateTestError, '__cmp__ failure'
185+ if a+365 != b or 365+a != b:
186+ raise DateTestError, '__add__ failure'
187+ if b-a != 365 or b-365 != a:
188+ raise DateTestError, '__sub__ failure'
189+ try:
190+ x = 1 - a
191+ raise DateTestError, 'int-date should have failed'
192+ except TypeError:
193+ pass
194+ try:
195+ x = a + b
196+ raise DateTestError, 'date+date should have failed'
197+ except TypeError:
198+ pass
199+ if a.weekday() != 'Tuesday':
200+ raise DateTestError, 'weekday() failure'
201+ if max(a,b) is not b or min(a,b) is not a:
202+ raise DateTestError, 'min/max failure'
203+ d = {a-1:b, b:a+1}
204+ if d[b-366] != b or d[a+(b-a)] != Date(10,1,1913):
205+ raise DateTestError, 'dictionary failure'
206+
207+ # verify date<->number conversions for first and last days for
208+ # all years in firstyear .. lastyear
209+
210+ lord = _days_before_year(firstyear)
211+ y = firstyear
212+ while y <= lastyear:
213+ ford = lord + 1
214+ lord = ford + _days_in_year(y) - 1
215+ fd, ld = Date(1,1,y), Date(12,31,y)
216+ if (fd.ord,ld.ord) != (ford,lord):
217+ raise DateTestError, ('date->num failed', y)
218+ fd, ld = _num2date(ford), _num2date(lord)
219+ if (1,1,y,12,31,y) != \
220+ (fd.month,fd.day,fd.year,ld.month,ld.day,ld.year):
221+ raise DateTestError, ('num->date failed', y)
222+ y = y + 1
sys/src/cmd/python/Demo/classes/Dbm.py+66−0
@@ -0,0 +1,66 @@
1+# A wrapper around the (optional) built-in class dbm, supporting keys
2+# and values of almost any type instead of just string.
3+# (Actually, this works only for keys and values that can be read back
4+# correctly after being converted to a string.)
5+
6+
7+class Dbm:
8+
9+ def __init__(self, filename, mode, perm):
10+ import dbm
11+ self.db = dbm.open(filename, mode, perm)
12+
13+ def __repr__(self):
14+ s = ''
15+ for key in self.keys():
16+ t = repr(key) + ': ' + repr(self[key])
17+ if s: t = ', ' + t
18+ s = s + t
19+ return '{' + s + '}'
20+
21+ def __len__(self):
22+ return len(self.db)
23+
24+ def __getitem__(self, key):
25+ return eval(self.db[repr(key)])
26+
27+ def __setitem__(self, key, value):
28+ self.db[repr(key)] = repr(value)
29+
30+ def __delitem__(self, key):
31+ del self.db[repr(key)]
32+
33+ def keys(self):
34+ res = []
35+ for key in self.db.keys():
36+ res.append(eval(key))
37+ return res
38+
39+ def has_key(self, key):
40+ return self.db.has_key(repr(key))
41+
42+
43+def test():
44+ d = Dbm('@dbm', 'rw', 0600)
45+ print d
46+ while 1:
47+ try:
48+ key = input('key: ')
49+ if d.has_key(key):
50+ value = d[key]
51+ print 'currently:', value
52+ value = input('value: ')
53+ if value == None:
54+ del d[key]
55+ else:
56+ d[key] = value
57+ except KeyboardInterrupt:
58+ print ''
59+ print d
60+ except EOFError:
61+ print '[eof]'
62+ break
63+ print d
64+
65+
66+test()
sys/src/cmd/python/Demo/classes/README+13−0
@@ -0,0 +1,13 @@
1+Examples of classes that implement special operators (see reference manual):
2+
3+Complex.py Complex numbers
4+Dates.py Date manipulation package by Tim Peters
5+Dbm.py Wrapper around built-in dbm, supporting arbitrary values
6+Range.py Example of a generator: re-implement built-in range()
7+Rat.py Rational numbers
8+Rev.py Yield the reverse of a sequence
9+Vec.py A simple vector class
10+bitvec.py A bit-vector class by Jan-Hein B\"uhrman
11+
12+(For straightforward examples of basic class features, such as use of
13+methods and inheritance, see the library code.)
sys/src/cmd/python/Demo/classes/Range.py+93−0
@@ -0,0 +1,93 @@
1+"""Example of a generator: re-implement the built-in range function
2+without actually constructing the list of values.
3+
4+OldStyleRange is coded in the way required to work in a 'for' loop before
5+iterators were introduced into the language; using __getitem__ and __len__ .
6+
7+"""
8+def handleargs(arglist):
9+ """Take list of arguments and extract/create proper start, stop, and step
10+ values and return in a tuple"""
11+ try:
12+ if len(arglist) == 1:
13+ return 0, int(arglist[0]), 1
14+ elif len(arglist) == 2:
15+ return int(arglist[0]), int(arglist[1]), 1
16+ elif len(arglist) == 3:
17+ if arglist[2] == 0:
18+ raise ValueError("step argument must not be zero")
19+ return tuple(int(x) for x in arglist)
20+ else:
21+ raise TypeError("range() accepts 1-3 arguments, given", len(arglist))
22+ except TypeError:
23+ raise TypeError("range() arguments must be numbers or strings "
24+ "representing numbers")
25+
26+def genrange(*a):
27+ """Function to implement 'range' as a generator"""
28+ start, stop, step = handleargs(a)
29+ value = start
30+ while value < stop:
31+ yield value
32+ value += step
33+
34+class oldrange:
35+ """Class implementing a range object.
36+ To the user the instances feel like immutable sequences
37+ (and you can't concatenate or slice them)
38+
39+ Done using the old way (pre-iterators; __len__ and __getitem__) to have an
40+ object be used by a 'for' loop.
41+
42+ """
43+
44+ def __init__(self, *a):
45+ """ Initialize start, stop, and step values along with calculating the
46+ nubmer of values (what __len__ will return) in the range"""
47+ self.start, self.stop, self.step = handleargs(a)
48+ self.len = max(0, (self.stop - self.start) // self.step)
49+
50+ def __repr__(self):
51+ """implement repr(x) which is also used by print"""
52+ return 'range(%r, %r, %r)' % (self.start, self.stop, self.step)
53+
54+ def __len__(self):
55+ """implement len(x)"""
56+ return self.len
57+
58+ def __getitem__(self, i):
59+ """implement x[i]"""
60+ if 0 <= i <= self.len:
61+ return self.start + self.step * i
62+ else:
63+ raise IndexError, 'range[i] index out of range'
64+
65+
66+def test():
67+ import time, __builtin__
68+ #Just a quick sanity check
69+ correct_result = __builtin__.range(5, 100, 3)
70+ oldrange_result = list(oldrange(5, 100, 3))
71+ genrange_result = list(genrange(5, 100, 3))
72+ if genrange_result != correct_result or oldrange_result != correct_result:
73+ raise Exception("error in implementation:\ncorrect = %s"
74+ "\nold-style = %s\ngenerator = %s" %
75+ (correct_result, oldrange_result, genrange_result))
76+ print "Timings for range(1000):"
77+ t1 = time.time()
78+ for i in oldrange(1000):
79+ pass
80+ t2 = time.time()
81+ for i in genrange(1000):
82+ pass
83+ t3 = time.time()
84+ for i in __builtin__.range(1000):
85+ pass
86+ t4 = time.time()
87+ print t2-t1, 'sec (old-style class)'
88+ print t3-t2, 'sec (generator)'
89+ print t4-t3, 'sec (built-in)'
90+
91+
92+if __name__ == '__main__':
93+ test()
sys/src/cmd/python/Demo/classes/Rat.py+310−0
@@ -0,0 +1,310 @@
1+'''\
2+This module implements rational numbers.
3+
4+The entry point of this module is the function
5+ rat(numerator, denominator)
6+If either numerator or denominator is of an integral or rational type,
7+the result is a rational number, else, the result is the simplest of
8+the types float and complex which can hold numerator/denominator.
9+If denominator is omitted, it defaults to 1.
10+Rational numbers can be used in calculations with any other numeric
11+type. The result of the calculation will be rational if possible.
12+
13+There is also a test function with calling sequence
14+ test()
15+The documentation string of the test function contains the expected
16+output.
17+'''
18+
19+# Contributed by Sjoerd Mullender
20+
21+from types import *
22+
23+def gcd(a, b):
24+ '''Calculate the Greatest Common Divisor.'''
25+ while b:
26+ a, b = b, a%b
27+ return a
28+
29+def rat(num, den = 1):
30+ # must check complex before float
31+ if isinstance(num, complex) or isinstance(den, complex):
32+ # numerator or denominator is complex: return a complex
33+ return complex(num) / complex(den)
34+ if isinstance(num, float) or isinstance(den, float):
35+ # numerator or denominator is float: return a float
36+ return float(num) / float(den)
37+ # otherwise return a rational
38+ return Rat(num, den)
39+
40+class Rat:
41+ '''This class implements rational numbers.'''
42+
43+ def __init__(self, num, den = 1):
44+ if den == 0:
45+ raise ZeroDivisionError, 'rat(x, 0)'
46+
47+ # normalize
48+
49+ # must check complex before float
50+ if (isinstance(num, complex) or
51+ isinstance(den, complex)):
52+ # numerator or denominator is complex:
53+ # normalized form has denominator == 1+0j
54+ self.__num = complex(num) / complex(den)
55+ self.__den = complex(1)
56+ return
57+ if isinstance(num, float) or isinstance(den, float):
58+ # numerator or denominator is float:
59+ # normalized form has denominator == 1.0
60+ self.__num = float(num) / float(den)
61+ self.__den = 1.0
62+ return
63+ if (isinstance(num, self.__class__) or
64+ isinstance(den, self.__class__)):
65+ # numerator or denominator is rational
66+ new = num / den
67+ if not isinstance(new, self.__class__):
68+ self.__num = new
69+ if isinstance(new, complex):
70+ self.__den = complex(1)
71+ else:
72+ self.__den = 1.0
73+ else:
74+ self.__num = new.__num
75+ self.__den = new.__den
76+ else:
77+ # make sure numerator and denominator don't
78+ # have common factors
79+ # this also makes sure that denominator > 0
80+ g = gcd(num, den)
81+ self.__num = num / g
82+ self.__den = den / g
83+ # try making numerator and denominator of IntType if they fit
84+ try:
85+ numi = int(self.__num)
86+ deni = int(self.__den)
87+ except (OverflowError, TypeError):
88+ pass
89+ else:
90+ if self.__num == numi and self.__den == deni:
91+ self.__num = numi
92+ self.__den = deni
93+
94+ def __repr__(self):
95+ return 'Rat(%s,%s)' % (self.__num, self.__den)
96+
97+ def __str__(self):
98+ if self.__den == 1:
99+ return str(self.__num)
100+ else:
101+ return '(%s/%s)' % (str(self.__num), str(self.__den))
102+
103+ # a + b
104+ def __add__(a, b):
105+ try:
106+ return rat(a.__num * b.__den + b.__num * a.__den,
107+ a.__den * b.__den)
108+ except OverflowError:
109+ return rat(long(a.__num) * long(b.__den) +
110+ long(b.__num) * long(a.__den),
111+ long(a.__den) * long(b.__den))
112+
113+ def __radd__(b, a):
114+ return Rat(a) + b
115+
116+ # a - b
117+ def __sub__(a, b):
118+ try:
119+ return rat(a.__num * b.__den - b.__num * a.__den,
120+ a.__den * b.__den)
121+ except OverflowError:
122+ return rat(long(a.__num) * long(b.__den) -
123+ long(b.__num) * long(a.__den),
124+ long(a.__den) * long(b.__den))
125+
126+ def __rsub__(b, a):
127+ return Rat(a) - b
128+
129+ # a * b
130+ def __mul__(a, b):
131+ try:
132+ return rat(a.__num * b.__num, a.__den * b.__den)
133+ except OverflowError:
134+ return rat(long(a.__num) * long(b.__num),
135+ long(a.__den) * long(b.__den))
136+
137+ def __rmul__(b, a):
138+ return Rat(a) * b
139+
140+ # a / b
141+ def __div__(a, b):
142+ try:
143+ return rat(a.__num * b.__den, a.__den * b.__num)
144+ except OverflowError:
145+ return rat(long(a.__num) * long(b.__den),
146+ long(a.__den) * long(b.__num))
147+
148+ def __rdiv__(b, a):
149+ return Rat(a) / b
150+
151+ # a % b
152+ def __mod__(a, b):
153+ div = a / b
154+ try:
155+ div = int(div)
156+ except OverflowError:
157+ div = long(div)
158+ return a - b * div
159+
160+ def __rmod__(b, a):
161+ return Rat(a) % b
162+
163+ # a ** b
164+ def __pow__(a, b):
165+ if b.__den != 1:
166+ if isinstance(a.__num, complex):
167+ a = complex(a)
168+ else:
169+ a = float(a)
170+ if isinstance(b.__num, complex):
171+ b = complex(b)
172+ else:
173+ b = float(b)
174+ return a ** b
175+ try:
176+ return rat(a.__num ** b.__num, a.__den ** b.__num)
177+ except OverflowError:
178+ return rat(long(a.__num) ** b.__num,
179+ long(a.__den) ** b.__num)
180+
181+ def __rpow__(b, a):
182+ return Rat(a) ** b
183+
184+ # -a
185+ def __neg__(a):
186+ try:
187+ return rat(-a.__num, a.__den)
188+ except OverflowError:
189+ # a.__num == sys.maxint
190+ return rat(-long(a.__num), a.__den)
191+
192+ # abs(a)
193+ def __abs__(a):
194+ return rat(abs(a.__num), a.__den)
195+
196+ # int(a)
197+ def __int__(a):
198+ return int(a.__num / a.__den)
199+
200+ # long(a)
201+ def __long__(a):
202+ return long(a.__num) / long(a.__den)
203+
204+ # float(a)
205+ def __float__(a):
206+ return float(a.__num) / float(a.__den)
207+
208+ # complex(a)
209+ def __complex__(a):
210+ return complex(a.__num) / complex(a.__den)
211+
212+ # cmp(a,b)
213+ def __cmp__(a, b):
214+ diff = Rat(a - b)
215+ if diff.__num < 0:
216+ return -1
217+ elif diff.__num > 0:
218+ return 1
219+ else:
220+ return 0
221+
222+ def __rcmp__(b, a):
223+ return cmp(Rat(a), b)
224+
225+ # a != 0
226+ def __nonzero__(a):
227+ return a.__num != 0
228+
229+ # coercion
230+ def __coerce__(a, b):
231+ return a, Rat(b)
232+
233+def test():
234+ '''\
235+ Test function for rat module.
236+
237+ The expected output is (module some differences in floating
238+ precission):
239+ -1
240+ -1
241+ 0 0L 0.1 (0.1+0j)
242+ [Rat(1,2), Rat(-3,10), Rat(1,25), Rat(1,4)]
243+ [Rat(-3,10), Rat(1,25), Rat(1,4), Rat(1,2)]
244+ 0
245+ (11/10)
246+ (11/10)
247+ 1.1
248+ OK
249+ 2 1.5 (3/2) (1.5+1.5j) (15707963/5000000)
250+ 2 2 2.0 (2+0j)
251+
252+ 4 0 4 1 4 0
253+ 3.5 0.5 3.0 1.33333333333 2.82842712475 1
254+ (7/2) (1/2) 3 (4/3) 2.82842712475 1
255+ (3.5+1.5j) (0.5-1.5j) (3+3j) (0.666666666667-0.666666666667j) (1.43248815986+2.43884761145j) 1
256+ 1.5 1 1.5 (1.5+0j)
257+
258+ 3.5 -0.5 3.0 0.75 2.25 -1
259+ 3.0 0.0 2.25 1.0 1.83711730709 0
260+ 3.0 0.0 2.25 1.0 1.83711730709 1
261+ (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1
262+ (3/2) 1 1.5 (1.5+0j)
263+
264+ (7/2) (-1/2) 3 (3/4) (9/4) -1
265+ 3.0 0.0 2.25 1.0 1.83711730709 -1
266+ 3 0 (9/4) 1 1.83711730709 0
267+ (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1
268+ (1.5+1.5j) (1.5+1.5j)
269+
270+ (3.5+1.5j) (-0.5+1.5j) (3+3j) (0.75+0.75j) 4.5j -1
271+ (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1
272+ (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1
273+ (3+3j) 0j 4.5j (1+0j) (-0.638110484918+0.705394566962j) 0
274+ '''
275+ print rat(-1L, 1)
276+ print rat(1, -1)
277+ a = rat(1, 10)
278+ print int(a), long(a), float(a), complex(a)
279+ b = rat(2, 5)
280+ l = [a+b, a-b, a*b, a/b]
281+ print l
282+ l.sort()
283+ print l
284+ print rat(0, 1)
285+ print a+1
286+ print a+1L
287+ print a+1.0
288+ try:
289+ print rat(1, 0)
290+ raise SystemError, 'should have been ZeroDivisionError'
291+ except ZeroDivisionError:
292+ print 'OK'
293+ print rat(2), rat(1.5), rat(3, 2), rat(1.5+1.5j), rat(31415926,10000000)
294+ list = [2, 1.5, rat(3,2), 1.5+1.5j]
295+ for i in list:
296+ print i,
297+ if not isinstance(i, complex):
298+ print int(i), float(i),
299+ print complex(i)
300+ print
301+ for j in list:
302+ print i + j, i - j, i * j, i / j, i ** j,
303+ if not (isinstance(i, complex) or
304+ isinstance(j, complex)):
305+ print cmp(i, j)
306+ print
307+
308+
309+if __name__ == '__main__':
310+ test()
sys/src/cmd/python/Demo/classes/Rev.py+95−0
@@ -0,0 +1,95 @@
1+'''
2+A class which presents the reverse of a sequence without duplicating it.
3+From: "Steven D. Majewski" <sdm7g@elvis.med.virginia.edu>
4+
5+It works on mutable or inmutable sequences.
6+
7+>>> chars = list(Rev('Hello World!'))
8+>>> print ''.join(chars)
9+!dlroW olleH
10+
11+The .forw is so you can use anonymous sequences in __init__, and still
12+keep a reference the forward sequence. )
13+If you give it a non-anonymous mutable sequence, the reverse sequence
14+will track the updated values. ( but not reassignment! - another
15+good reason to use anonymous values in creating the sequence to avoid
16+confusion. Maybe it should be change to copy input sequence to break
17+the connection completely ? )
18+
19+>>> nnn = range(3)
20+>>> rnn = Rev(nnn)
21+>>> for n in rnn: print n
22+...
23+2
24+1
25+0
26+>>> for n in range(4, 6): nnn.append(n) # update nnn
27+...
28+>>> for n in rnn: print n # prints reversed updated values
29+...
30+5
31+4
32+2
33+1
34+0
35+>>> nnn = nnn[1:-1]
36+>>> nnn
37+[1, 2, 4]
38+>>> for n in rnn: print n # prints reversed values of old nnn
39+...
40+5
41+4
42+2
43+1
44+0
45+
46+#
47+>>> WH = Rev('Hello World!')
48+>>> print WH.forw, WH.back
49+Hello World! !dlroW olleH
50+>>> nnn = Rev(range(1, 10))
51+>>> print nnn.forw
52+[1, 2, 3, 4, 5, 6, 7, 8, 9]
53+>>> print nnn.back
54+[9, 8, 7, 6, 5, 4, 3, 2, 1]
55+
56+>>> rrr = Rev(nnn)
57+>>> rrr
58+<1, 2, 3, 4, 5, 6, 7, 8, 9>
59+
60+'''
61+
62+class Rev:
63+ def __init__(self, seq):
64+ self.forw = seq
65+ self.back = self
66+
67+ def __len__(self):
68+ return len(self.forw)
69+
70+ def __getitem__(self, j):
71+ return self.forw[-(j + 1)]
72+
73+ def __repr__(self):
74+ seq = self.forw
75+ if isinstance(seq, list):
76+ wrap = '[]'
77+ sep = ', '
78+ elif isinstance(seq, tuple):
79+ wrap = '()'
80+ sep = ', '
81+ elif isinstance(seq, str):
82+ wrap = ''
83+ sep = ''
84+ else:
85+ wrap = '<>'
86+ sep = ', '
87+ outstrs = [str(item) for item in self.back]
88+ return wrap[:1] + sep.join(outstrs) + wrap[-1:]
89+
90+def _test():
91+ import doctest, Rev
92+ return doctest.testmod(Rev)
93+
94+if __name__ == "__main__":
95+ _test()
sys/src/cmd/python/Demo/classes/Vec.py+54−0
@@ -0,0 +1,54 @@
1+# A simple vector class
2+
3+
4+def vec(*v):
5+ return Vec(*v)
6+
7+
8+class Vec:
9+
10+ def __init__(self, *v):
11+ self.v = list(v)
12+
13+ def fromlist(self, v):
14+ if not isinstance(v, list):
15+ raise TypeError
16+ self.v = v[:]
17+ return self
18+
19+ def __repr__(self):
20+ return 'vec(' + repr(self.v)[1:-1] + ')'
21+
22+ def __len__(self):
23+ return len(self.v)
24+
25+ def __getitem__(self, i):
26+ return self.v[i]
27+
28+ def __add__(self, other):
29+ # Element-wise addition
30+ v = map(lambda x, y: x+y, self, other)
31+ return Vec().fromlist(v)
32+
33+ def __sub__(self, other):
34+ # Element-wise subtraction
35+ v = map(lambda x, y: x-y, self, other)
36+ return Vec().fromlist(v)
37+
38+ def __mul__(self, scalar):
39+ # Multiply by scalar
40+ v = map(lambda x: x*scalar, self.v)
41+ return Vec().fromlist(v)
42+
43+
44+
45+def test():
46+ a = vec(1, 2, 3)
47+ b = vec(3, 2, 1)
48+ print a
49+ print b
50+ print a+b
51+ print a-b
52+ print a*3.0
53+
54+test()
sys/src/cmd/python/Demo/classes/bitvec.py+332−0
@@ -0,0 +1,332 @@
1+#
2+# this is a rather strict implementation of a bit vector class
3+# it is accessed the same way as an array of python-ints, except
4+# the value must be 0 or 1
5+#
6+
7+import sys; rprt = sys.stderr.write #for debugging
8+
9+error = 'bitvec.error'
10+
11+
12+def _check_value(value):
13+ if type(value) != type(0) or not 0 <= value < 2:
14+ raise error, 'bitvec() items must have int value 0 or 1'
15+
16+
17+import math
18+
19+def _compute_len(param):
20+ mant, l = math.frexp(float(param))
21+ bitmask = 1L << l
22+ if bitmask <= param:
23+ raise 'FATAL', '(param, l) = %r' % ((param, l),)
24+ while l:
25+ bitmask = bitmask >> 1
26+ if param & bitmask:
27+ break
28+ l = l - 1
29+ return l
30+
31+
32+def _check_key(len, key):
33+ if type(key) != type(0):
34+ raise TypeError, 'sequence subscript not int'
35+ if key < 0:
36+ key = key + len
37+ if not 0 <= key < len:
38+ raise IndexError, 'list index out of range'
39+ return key
40+
41+def _check_slice(len, i, j):
42+ #the type is ok, Python already checked that
43+ i, j = max(i, 0), min(len, j)
44+ if i > j:
45+ i = j
46+ return i, j
47+
48+
49+class BitVec:
50+
51+ def __init__(self, *params):
52+ self._data = 0L
53+ self._len = 0
54+ if not len(params):
55+ pass
56+ elif len(params) == 1:
57+ param, = params
58+ if type(param) == type([]):
59+ value = 0L
60+ bit_mask = 1L
61+ for item in param:
62+ # strict check
63+ #_check_value(item)
64+ if item:
65+ value = value | bit_mask
66+ bit_mask = bit_mask << 1
67+ self._data = value
68+ self._len = len(param)
69+ elif type(param) == type(0L):
70+ if param < 0:
71+ raise error, 'bitvec() can\'t handle negative longs'
72+ self._data = param
73+ self._len = _compute_len(param)
74+ else:
75+ raise error, 'bitvec() requires array or long parameter'
76+ elif len(params) == 2:
77+ param, length = params
78+ if type(param) == type(0L):
79+ if param < 0:
80+ raise error, \
81+ 'can\'t handle negative longs'
82+ self._data = param
83+ if type(length) != type(0):
84+ raise error, 'bitvec()\'s 2nd parameter must be int'
85+ computed_length = _compute_len(param)
86+ if computed_length > length:
87+ print 'warning: bitvec() value is longer than the length indicates, truncating value'
88+ self._data = self._data & \
89+ ((1L << length) - 1)
90+ self._len = length
91+ else:
92+ raise error, 'bitvec() requires array or long parameter'
93+ else:
94+ raise error, 'bitvec() requires 0 -- 2 parameter(s)'
95+
96+
97+ def append(self, item):
98+ #_check_value(item)
99+ #self[self._len:self._len] = [item]
100+ self[self._len:self._len] = \
101+ BitVec(long(not not item), 1)
102+
103+
104+ def count(self, value):
105+ #_check_value(value)
106+ if value:
107+ data = self._data
108+ else:
109+ data = (~self)._data
110+ count = 0
111+ while data:
112+ data, count = data >> 1, count + (data & 1 != 0)
113+ return count
114+
115+
116+ def index(self, value):
117+ #_check_value(value):
118+ if value:
119+ data = self._data
120+ else:
121+ data = (~self)._data
122+ index = 0
123+ if not data:
124+ raise ValueError, 'list.index(x): x not in list'
125+ while not (data & 1):
126+ data, index = data >> 1, index + 1
127+ return index
128+
129+
130+ def insert(self, index, item):
131+ #_check_value(item)
132+ #self[index:index] = [item]
133+ self[index:index] = BitVec(long(not not item), 1)
134+
135+
136+ def remove(self, value):
137+ del self[self.index(value)]
138+
139+
140+ def reverse(self):
141+ #ouch, this one is expensive!
142+ #for i in self._len>>1: self[i], self[l-i] = self[l-i], self[i]
143+ data, result = self._data, 0L
144+ for i in range(self._len):
145+ if not data:
146+ result = result << (self._len - i)
147+ break
148+ result, data = (result << 1) | (data & 1), data >> 1
149+ self._data = result
150+
151+
152+ def sort(self):
153+ c = self.count(1)
154+ self._data = ((1L << c) - 1) << (self._len - c)
155+
156+
157+ def copy(self):
158+ return BitVec(self._data, self._len)
159+
160+
161+ def seq(self):
162+ result = []
163+ for i in self:
164+ result.append(i)
165+ return result
166+
167+
168+ def __repr__(self):
169+ ##rprt('<bitvec class instance object>.' + '__repr__()\n')
170+ return 'bitvec(%r, %r)' % (self._data, self._len)
171+
172+ def __cmp__(self, other, *rest):
173+ #rprt('%r.__cmp__%r\n' % (self, (other,) + rest))
174+ if type(other) != type(self):
175+ other = apply(bitvec, (other, ) + rest)
176+ #expensive solution... recursive binary, with slicing
177+ length = self._len
178+ if length == 0 or other._len == 0:
179+ return cmp(length, other._len)
180+ if length != other._len:
181+ min_length = min(length, other._len)
182+ return cmp(self[:min_length], other[:min_length]) or \
183+ cmp(self[min_length:], other[min_length:])
184+ #the lengths are the same now...
185+ if self._data == other._data:
186+ return 0
187+ if length == 1:
188+ return cmp(self[0], other[0])
189+ else:
190+ length = length >> 1
191+ return cmp(self[:length], other[:length]) or \
192+ cmp(self[length:], other[length:])
193+
194+
195+ def __len__(self):
196+ #rprt('%r.__len__()\n' % (self,))
197+ return self._len
198+
199+ def __getitem__(self, key):
200+ #rprt('%r.__getitem__(%r)\n' % (self, key))
201+ key = _check_key(self._len, key)
202+ return self._data & (1L << key) != 0
203+
204+ def __setitem__(self, key, value):
205+ #rprt('%r.__setitem__(%r, %r)\n' % (self, key, value))
206+ key = _check_key(self._len, key)
207+ #_check_value(value)
208+ if value:
209+ self._data = self._data | (1L << key)
210+ else:
211+ self._data = self._data & ~(1L << key)
212+
213+ def __delitem__(self, key):
214+ #rprt('%r.__delitem__(%r)\n' % (self, key))
215+ key = _check_key(self._len, key)
216+ #el cheapo solution...
217+ self._data = self[:key]._data | self[key+1:]._data >> key
218+ self._len = self._len - 1
219+
220+ def __getslice__(self, i, j):
221+ #rprt('%r.__getslice__(%r, %r)\n' % (self, i, j))
222+ i, j = _check_slice(self._len, i, j)
223+ if i >= j:
224+ return BitVec(0L, 0)
225+ if i:
226+ ndata = self._data >> i
227+ else:
228+ ndata = self._data
229+ nlength = j - i
230+ if j != self._len:
231+ #we'll have to invent faster variants here
232+ #e.g. mod_2exp
233+ ndata = ndata & ((1L << nlength) - 1)
234+ return BitVec(ndata, nlength)
235+
236+ def __setslice__(self, i, j, sequence, *rest):
237+ #rprt('%s.__setslice__%r\n' % (self, (i, j, sequence) + rest))
238+ i, j = _check_slice(self._len, i, j)
239+ if type(sequence) != type(self):
240+ sequence = apply(bitvec, (sequence, ) + rest)
241+ #sequence is now of our own type
242+ ls_part = self[:i]
243+ ms_part = self[j:]
244+ self._data = ls_part._data | \
245+ ((sequence._data | \
246+ (ms_part._data << sequence._len)) << ls_part._len)
247+ self._len = self._len - j + i + sequence._len
248+
249+ def __delslice__(self, i, j):
250+ #rprt('%r.__delslice__(%r, %r)\n' % (self, i, j))
251+ i, j = _check_slice(self._len, i, j)
252+ if i == 0 and j == self._len:
253+ self._data, self._len = 0L, 0
254+ elif i < j:
255+ self._data = self[:i]._data | (self[j:]._data >> i)
256+ self._len = self._len - j + i
257+
258+ def __add__(self, other):
259+ #rprt('%r.__add__(%r)\n' % (self, other))
260+ retval = self.copy()
261+ retval[self._len:self._len] = other
262+ return retval
263+
264+ def __mul__(self, multiplier):
265+ #rprt('%r.__mul__(%r)\n' % (self, multiplier))
266+ if type(multiplier) != type(0):
267+ raise TypeError, 'sequence subscript not int'
268+ if multiplier <= 0:
269+ return BitVec(0L, 0)
270+ elif multiplier == 1:
271+ return self.copy()
272+ #handle special cases all 0 or all 1...
273+ if self._data == 0L:
274+ return BitVec(0L, self._len * multiplier)
275+ elif (~self)._data == 0L:
276+ return ~BitVec(0L, self._len * multiplier)
277+ #otherwise el cheapo again...
278+ retval = BitVec(0L, 0)
279+ while multiplier:
280+ retval, multiplier = retval + self, multiplier - 1
281+ return retval
282+
283+ def __and__(self, otherseq, *rest):
284+ #rprt('%r.__and__%r\n' % (self, (otherseq,) + rest))
285+ if type(otherseq) != type(self):
286+ otherseq = apply(bitvec, (otherseq, ) + rest)
287+ #sequence is now of our own type
288+ return BitVec(self._data & otherseq._data, \
289+ min(self._len, otherseq._len))
290+
291+
292+ def __xor__(self, otherseq, *rest):
293+ #rprt('%r.__xor__%r\n' % (self, (otherseq,) + rest))
294+ if type(otherseq) != type(self):
295+ otherseq = apply(bitvec, (otherseq, ) + rest)
296+ #sequence is now of our own type
297+ return BitVec(self._data ^ otherseq._data, \
298+ max(self._len, otherseq._len))
299+
300+
301+ def __or__(self, otherseq, *rest):
302+ #rprt('%r.__or__%r\n' % (self, (otherseq,) + rest))
303+ if type(otherseq) != type(self):
304+ otherseq = apply(bitvec, (otherseq, ) + rest)
305+ #sequence is now of our own type
306+ return BitVec(self._data | otherseq._data, \
307+ max(self._len, otherseq._len))
308+
309+
310+ def __invert__(self):
311+ #rprt('%r.__invert__()\n' % (self,))
312+ return BitVec(~self._data & ((1L << self._len) - 1), \
313+ self._len)
314+
315+ def __coerce__(self, otherseq, *rest):
316+ #needed for *some* of the arithmetic operations
317+ #rprt('%r.__coerce__%r\n' % (self, (otherseq,) + rest))
318+ if type(otherseq) != type(self):
319+ otherseq = apply(bitvec, (otherseq, ) + rest)
320+ return self, otherseq
321+
322+ def __int__(self):
323+ return int(self._data)
324+
325+ def __long__(self):
326+ return long(self._data)
327+
328+ def __float__(self):
329+ return float(self._data)
330+
331+
332+bitvec = BitVec
sys/src/cmd/python/Demo/comparisons/README+60−0
@@ -0,0 +1,60 @@
1+Subject: Re: What language would you use?
2+From: Tom Christiansen <tchrist@mox.perl.com>
3+Date: 6 Nov 1994 15:14:51 GMT
4+Newsgroups: comp.lang.python,comp.lang.tcl,comp.lang.scheme,comp.lang.misc,comp.lang.perl
5+Message-Id: <39irtb$3t4@csnews.cs.Colorado.EDU>
6+References: <39b7ha$j9v@zeno.nscf.org> <39hhjp$lgn@csnews.cs.Colorado.EDU> <39hvsu$dus@mathserv.mps.ohio-state.edu>
7+
8+[...]
9+If you're really into benchmarks, I'd love it if someone were to code up
10+the following problems in tcl, python, and scheme (and whatever else you'd
11+like). Separate versions (one optimized for speed, one for beauty :-) are
12+ok. Post your code so we can time it on our own systems.
13+
14+0) Factorial Test (numerics and function calls)
15+
16+ (we did this already)
17+
18+1) Regular Expressions Test
19+
20+ Read a file of (extended per egrep) regular expressions (one per line),
21+ and apply those to all files whose names are listed on the command line.
22+ Basically, an 'egrep -f' simulator. Test it with 20 "vt100" patterns
23+ against a five /etc/termcap files. Tests using more elaborate patters
24+ would also be interesting. Your code should not break if given hundreds
25+ of regular expressions or binary files to scan.
26+
27+2) Sorting Test
28+
29+ Sort an input file that consists of lines like this
30+
31+ var1=23 other=14 ditto=23 fred=2
32+
33+ such that each output line is sorted WRT to the number. Order
34+ of output lines does not change. Resolve collisions using the
35+ variable name. e.g.
36+
37+ fred=2 other=14 ditto=23 var1=23
38+
39+ Lines may be up to several kilobytes in length and contain
40+ zillions of variables.
41+
42+3) System Test
43+
44+ Given a list of directories, report any bogus symbolic links contained
45+ anywhere in those subtrees. A bogus symbolic link is one that cannot
46+ be resolved because it points to a nonexistent or otherwise
47+ unresolvable file. Do *not* use an external find executable.
48+ Directories may be very very deep. Print a warning immediately if the
49+ system you're running on doesn't support symbolic links.
50+
51+
52+I'll post perl solutions if people post the others.
53+
54+
55+--tom
56+--
57+Tom Christiansen Perl Consultant, Gamer, Hiker tchrist@mox.perl.com
58+
59+ "But Billy! A *small* allowance prepares you for a lifetime of small
60+ salaries and for your Social Security payments." --Family Circus
sys/src/cmd/python/Demo/comparisons/patterns+4−0
@@ -0,0 +1,4 @@
1+^def
2+^class
3+^import
4+^from
sys/src/cmd/python/Demo/comparisons/regextest.py+47−0
@@ -0,0 +1,47 @@
1+#! /usr/bin/env python
2+
3+# 1) Regular Expressions Test
4+#
5+# Read a file of (extended per egrep) regular expressions (one per line),
6+# and apply those to all files whose names are listed on the command line.
7+# Basically, an 'egrep -f' simulator. Test it with 20 "vt100" patterns
8+# against a five /etc/termcap files. Tests using more elaborate patters
9+# would also be interesting. Your code should not break if given hundreds
10+# of regular expressions or binary files to scan.
11+
12+# This implementation:
13+# - combines all patterns into a single one using ( ... | ... | ... )
14+# - reads patterns from stdin, scans files given as command line arguments
15+# - produces output in the format <file>:<lineno>:<line>
16+# - is only about 2.5 times as slow as egrep (though I couldn't run
17+# Tom's test -- this system, a vanilla SGI, only has /etc/terminfo)
18+
19+import string
20+import sys
21+import re
22+
23+def main():
24+ pats = map(chomp, sys.stdin.readlines())
25+ bigpat = '(' + '|'.join(pats) + ')'
26+ prog = re.compile(bigpat)
27+
28+ for file in sys.argv[1:]:
29+ try:
30+ fp = open(file, 'r')
31+ except IOError, msg:
32+ print "%s: %s" % (file, msg)
33+ continue
34+ lineno = 0
35+ while 1:
36+ line = fp.readline()
37+ if not line:
38+ break
39+ lineno = lineno + 1
40+ if prog.search(line):
41+ print "%s:%s:%s" % (file, lineno, line),
42+
43+def chomp(s):
44+ return s.rstrip('\n')
45+
46+if __name__ == '__main__':
47+ main()
sys/src/cmd/python/Demo/comparisons/sortingtest.py+51−0
@@ -0,0 +1,51 @@
1+#! /usr/bin/env python
2+
3+# 2) Sorting Test
4+#
5+# Sort an input file that consists of lines like this
6+#
7+# var1=23 other=14 ditto=23 fred=2
8+#
9+# such that each output line is sorted WRT to the number. Order
10+# of output lines does not change. Resolve collisions using the
11+# variable name. e.g.
12+#
13+# fred=2 other=14 ditto=23 var1=23
14+#
15+# Lines may be up to several kilobytes in length and contain
16+# zillions of variables.
17+
18+# This implementation:
19+# - Reads stdin, writes stdout
20+# - Uses any amount of whitespace to separate fields
21+# - Allows signed numbers
22+# - Treats illegally formatted fields as field=0
23+# - Outputs the sorted fields with exactly one space between them
24+# - Handles blank input lines correctly
25+
26+import re
27+import string
28+import sys
29+
30+def main():
31+ prog = re.compile('^(.*)=([-+]?[0-9]+)')
32+ def makekey(item, prog=prog):
33+ match = prog.match(item)
34+ if match:
35+ var, num = match.group(1, 2)
36+ return string.atoi(num), var
37+ else:
38+ # Bad input -- pretend it's a var with value 0
39+ return 0, item
40+ while 1:
41+ line = sys.stdin.readline()
42+ if not line:
43+ break
44+ items = line.split()
45+ items = map(makekey, items)
46+ items.sort()
47+ for num, var in items:
48+ print "%s=%s" % (var, num),
49+ print
50+
51+main()
sys/src/cmd/python/Demo/comparisons/systemtest.py+74−0
@@ -0,0 +1,74 @@
1+#! /usr/bin/env python
2+
3+# 3) System Test
4+#
5+# Given a list of directories, report any bogus symbolic links contained
6+# anywhere in those subtrees. A bogus symbolic link is one that cannot
7+# be resolved because it points to a nonexistent or otherwise
8+# unresolvable file. Do *not* use an external find executable.
9+# Directories may be very very deep. Print a warning immediately if the
10+# system you're running on doesn't support symbolic links.
11+
12+# This implementation:
13+# - takes one optional argument, using the current directory as default
14+# - uses chdir to increase performance
15+# - sorts the names per directory
16+# - prints output lines of the form "path1 -> path2" as it goes
17+# - prints error messages about directories it can't list or chdir into
18+
19+import os
20+import sys
21+from stat import *
22+
23+def main():
24+ try:
25+ # Note: can't test for presence of lstat -- it's always there
26+ dummy = os.readlink
27+ except AttributeError:
28+ print "This system doesn't have symbolic links"
29+ sys.exit(0)
30+ if sys.argv[1:]:
31+ prefix = sys.argv[1]
32+ else:
33+ prefix = ''
34+ if prefix:
35+ os.chdir(prefix)
36+ if prefix[-1:] != '/': prefix = prefix + '/'
37+ reportboguslinks(prefix)
38+ else:
39+ reportboguslinks('')
40+
41+def reportboguslinks(prefix):
42+ try:
43+ names = os.listdir('.')
44+ except os.error, msg:
45+ print "%s%s: can't list: %s" % (prefix, '.', msg)
46+ return
47+ names.sort()
48+ for name in names:
49+ if name == os.curdir or name == os.pardir:
50+ continue
51+ try:
52+ mode = os.lstat(name)[ST_MODE]
53+ except os.error:
54+ print "%s%s: can't stat: %s" % (prefix, name, msg)
55+ continue
56+ if S_ISLNK(mode):
57+ try:
58+ os.stat(name)
59+ except os.error:
60+ print "%s%s -> %s" % \
61+ (prefix, name, os.readlink(name))
62+ elif S_ISDIR(mode):
63+ try:
64+ os.chdir(name)
65+ except os.error, msg:
66+ print "%s%s: can't chdir: %s" % \
67+ (prefix, name, msg)
68+ continue
69+ try:
70+ reportboguslinks(prefix + name + '/')
71+ finally:
72+ os.chdir('..')
73+
74+main()
sys/src/cmd/python/Demo/curses/README+25−0
@@ -0,0 +1,25 @@
1+This is a collection of demos and tests for the curses module.
2+
3+ncurses demos
4+=============
5+
6+These demos are converted from the C versions in the ncurses
7+distribution, and were contributed by Thomas Gellekum <tg@FreeBSD.org>
8+I didn't strive for a `pythonic' style, but bluntly copied the
9+originals. I won't attempt to `beautify' the program anytime soon, but
10+I wouldn't mind someone else making an effort in that direction, of
11+course.
12+
13+ncurses.py -- currently only a panels demo
14+rain.py -- raindrops keep falling on my desktop
15+tclock.py -- ASCII clock, by Howard Jones
16+xmas.py -- I'm dreaming of an ASCII christmas
17+
18+Please submit bugfixes and new contributions to the Python bug tracker.
19+
20+
21+Other demos
22+===========
23+
24+life.py -- Simple game of Life
25+repeat.py -- Repeatedly execute a shell command (like watch(1))
sys/src/cmd/python/Demo/curses/life.py+216−0
@@ -0,0 +1,216 @@
1+#!/usr/bin/env python
2+# life.py -- A curses-based version of Conway's Game of Life.
3+# Contributed by AMK
4+#
5+# An empty board will be displayed, and the following commands are available:
6+# E : Erase the board
7+# R : Fill the board randomly
8+# S : Step for a single generation
9+# C : Update continuously until a key is struck
10+# Q : Quit
11+# Cursor keys : Move the cursor around the board
12+# Space or Enter : Toggle the contents of the cursor's position
13+#
14+# TODO :
15+# Support the mouse
16+# Use colour if available
17+# Make board updates faster
18+#
19+
20+import random, string, traceback
21+import curses
22+
23+class LifeBoard:
24+ """Encapsulates a Life board
25+
26+ Attributes:
27+ X,Y : horizontal and vertical size of the board
28+ state : dictionary mapping (x,y) to 0 or 1
29+
30+ Methods:
31+ display(update_board) -- If update_board is true, compute the
32+ next generation. Then display the state
33+ of the board and refresh the screen.
34+ erase() -- clear the entire board
35+ makeRandom() -- fill the board randomly
36+ set(y,x) -- set the given cell to Live; doesn't refresh the screen
37+ toggle(y,x) -- change the given cell from live to dead, or vice
38+ versa, and refresh the screen display
39+
40+ """
41+ def __init__(self, scr, char=ord('*')):
42+ """Create a new LifeBoard instance.
43+
44+ scr -- curses screen object to use for display
45+ char -- character used to render live cells (default: '*')
46+ """
47+ self.state = {}
48+ self.scr = scr
49+ Y, X = self.scr.getmaxyx()
50+ self.X, self.Y = X-2, Y-2-1
51+ self.char = char
52+ self.scr.clear()
53+
54+ # Draw a border around the board
55+ border_line = '+'+(self.X*'-')+'+'
56+ self.scr.addstr(0, 0, border_line)
57+ self.scr.addstr(self.Y+1,0, border_line)
58+ for y in range(0, self.Y):
59+ self.scr.addstr(1+y, 0, '|')
60+ self.scr.addstr(1+y, self.X+1, '|')
61+ self.scr.refresh()
62+
63+ def set(self, y, x):
64+ """Set a cell to the live state"""
65+ if x<0 or self.X<=x or y<0 or self.Y<=y:
66+ raise ValueError, "Coordinates out of range %i,%i"% (y,x)
67+ self.state[x,y] = 1
68+
69+ def toggle(self, y, x):
70+ """Toggle a cell's state between live and dead"""
71+ if x<0 or self.X<=x or y<0 or self.Y<=y:
72+ raise ValueError, "Coordinates out of range %i,%i"% (y,x)
73+ if self.state.has_key( (x,y) ):
74+ del self.state[x,y]
75+ self.scr.addch(y+1, x+1, ' ')
76+ else:
77+ self.state[x,y] = 1
78+ self.scr.addch(y+1, x+1, self.char)
79+ self.scr.refresh()
80+
81+ def erase(self):
82+ """Clear the entire board and update the board display"""
83+ self.state = {}
84+ self.display(update_board=False)
85+
86+ def display(self, update_board=True):
87+ """Display the whole board, optionally computing one generation"""
88+ M,N = self.X, self.Y
89+ if not update_board:
90+ for i in range(0, M):
91+ for j in range(0, N):
92+ if self.state.has_key( (i,j) ):
93+ self.scr.addch(j+1, i+1, self.char)
94+ else:
95+ self.scr.addch(j+1, i+1, ' ')
96+ self.scr.refresh()
97+ return
98+
99+ d = {}
100+ self.boring = 1
101+ for i in range(0, M):
102+ L = range( max(0, i-1), min(M, i+2) )
103+ for j in range(0, N):
104+ s = 0
105+ live = self.state.has_key( (i,j) )
106+ for k in range( max(0, j-1), min(N, j+2) ):
107+ for l in L:
108+ if self.state.has_key( (l,k) ):
109+ s += 1
110+ s -= live
111+ if s == 3:
112+ # Birth
113+ d[i,j] = 1
114+ self.scr.addch(j+1, i+1, self.char)
115+ if not live: self.boring = 0
116+ elif s == 2 and live: d[i,j] = 1 # Survival
117+ elif live:
118+ # Death
119+ self.scr.addch(j+1, i+1, ' ')
120+ self.boring = 0
121+ self.state = d
122+ self.scr.refresh()
123+
124+ def makeRandom(self):
125+ "Fill the board with a random pattern"
126+ self.state = {}
127+ for i in range(0, self.X):
128+ for j in range(0, self.Y):
129+ if random.random() > 0.5:
130+ self.set(j,i)
131+
132+
133+def erase_menu(stdscr, menu_y):
134+ "Clear the space where the menu resides"
135+ stdscr.move(menu_y, 0)
136+ stdscr.clrtoeol()
137+ stdscr.move(menu_y+1, 0)
138+ stdscr.clrtoeol()
139+
140+def display_menu(stdscr, menu_y):
141+ "Display the menu of possible keystroke commands"
142+ erase_menu(stdscr, menu_y)
143+ stdscr.addstr(menu_y, 4,
144+ 'Use the cursor keys to move, and space or Enter to toggle a cell.')
145+ stdscr.addstr(menu_y+1, 4,
146+ 'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit')
147+
148+def keyloop(stdscr):
149+ # Clear the screen and display the menu of keys
150+ stdscr.clear()
151+ stdscr_y, stdscr_x = stdscr.getmaxyx()
152+ menu_y = (stdscr_y-3)-1
153+ display_menu(stdscr, menu_y)
154+
155+ # Allocate a subwindow for the Life board and create the board object
156+ subwin = stdscr.subwin(stdscr_y-3, stdscr_x, 0, 0)
157+ board = LifeBoard(subwin, char=ord('*'))
158+ board.display(update_board=False)
159+
160+ # xpos, ypos are the cursor's position
161+ xpos, ypos = board.X/2, board.Y/2
162+
163+ # Main loop:
164+ while (1):
165+ stdscr.move(1+ypos, 1+xpos) # Move the cursor
166+ c = stdscr.getch() # Get a keystroke
167+ if 0<c<256:
168+ c = chr(c)
169+ if c in ' \n':
170+ board.toggle(ypos, xpos)
171+ elif c in 'Cc':
172+ erase_menu(stdscr, menu_y)
173+ stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously '
174+ 'updating the screen.')
175+ stdscr.refresh()
176+ # Activate nodelay mode; getch() will return -1
177+ # if no keystroke is available, instead of waiting.
178+ stdscr.nodelay(1)
179+ while (1):
180+ c = stdscr.getch()
181+ if c != -1:
182+ break
183+ stdscr.addstr(0,0, '/')
184+ stdscr.refresh()
185+ board.display()
186+ stdscr.addstr(0,0, '+')
187+ stdscr.refresh()
188+
189+ stdscr.nodelay(0) # Disable nodelay mode
190+ display_menu(stdscr, menu_y)
191+
192+ elif c in 'Ee':
193+ board.erase()
194+ elif c in 'Qq':
195+ break
196+ elif c in 'Rr':
197+ board.makeRandom()
198+ board.display(update_board=False)
199+ elif c in 'Ss':
200+ board.display()
201+ else: pass # Ignore incorrect keys
202+ elif c == curses.KEY_UP and ypos>0: ypos -= 1
203+ elif c == curses.KEY_DOWN and ypos<board.Y-1: ypos += 1
204+ elif c == curses.KEY_LEFT and xpos>0: xpos -= 1
205+ elif c == curses.KEY_RIGHT and xpos<board.X-1: xpos += 1
206+ else:
207+ # Ignore incorrect keys
208+ pass
209+
210+
211+def main(stdscr):
212+ keyloop(stdscr) # Enter the main loop
213+
214+
215+if __name__ == '__main__':
216+ curses.wrapper(main)
sys/src/cmd/python/Demo/curses/ncurses.py+273−0
@@ -0,0 +1,273 @@
1+#!/usr/bin/env python
2+#
3+# $Id: ncurses.py 36559 2004-07-18 05:56:09Z tim_one $
4+#
5+# (n)curses exerciser in Python, an interactive test for the curses
6+# module. Currently, only the panel demos are ported.
7+
8+import curses
9+from curses import panel
10+
11+def wGetchar(win = None):
12+ if win == None: win = stdscr
13+ return win.getch()
14+
15+def Getchar():
16+ wGetchar()
17+
18+#
19+# Panels tester
20+#
21+def wait_a_while():
22+ if nap_msec == 1:
23+ Getchar()
24+ else:
25+ curses.napms(nap_msec)
26+
27+def saywhat(text):
28+ stdscr.move(curses.LINES - 1, 0)
29+ stdscr.clrtoeol()
30+ stdscr.addstr(text)
31+
32+def mkpanel(color, rows, cols, tly, tlx):
33+ win = curses.newwin(rows, cols, tly, tlx)
34+ pan = panel.new_panel(win)
35+ if curses.has_colors():
36+ if color == curses.COLOR_BLUE:
37+ fg = curses.COLOR_WHITE
38+ else:
39+ fg = curses.COLOR_BLACK
40+ bg = color
41+ curses.init_pair(color, fg, bg)
42+ win.bkgdset(ord(' '), curses.color_pair(color))
43+ else:
44+ win.bkgdset(ord(' '), curses.A_BOLD)
45+
46+ return pan
47+
48+def pflush():
49+ panel.update_panels()
50+ curses.doupdate()
51+
52+def fill_panel(pan):
53+ win = pan.window()
54+ num = pan.userptr()[1]
55+
56+ win.move(1, 1)
57+ win.addstr("-pan%c-" % num)
58+ win.clrtoeol()
59+ win.box()
60+
61+ maxy, maxx = win.getmaxyx()
62+ for y in range(2, maxy - 1):
63+ for x in range(1, maxx - 1):
64+ win.move(y, x)
65+ win.addch(num)
66+
67+def demo_panels(win):
68+ global stdscr, nap_msec, mod
69+ stdscr = win
70+ nap_msec = 1
71+ mod = ["test", "TEST", "(**)", "*()*", "<-->", "LAST"]
72+
73+ stdscr.refresh()
74+
75+ for y in range(0, curses.LINES - 1):
76+ for x in range(0, curses.COLS):
77+ stdscr.addstr("%d" % ((y + x) % 10))
78+ for y in range(0, 1):
79+ p1 = mkpanel(curses.COLOR_RED,
80+ curses.LINES / 2 - 2,
81+ curses.COLS / 8 + 1,
82+ 0,
83+ 0)
84+ p1.set_userptr("p1")
85+
86+ p2 = mkpanel(curses.COLOR_GREEN,
87+ curses.LINES / 2 + 1,
88+ curses.COLS / 7,
89+ curses.LINES / 4,
90+ curses.COLS / 10)
91+ p2.set_userptr("p2")
92+
93+ p3 = mkpanel(curses.COLOR_YELLOW,
94+ curses.LINES / 4,
95+ curses.COLS / 10,
96+ curses.LINES / 2,
97+ curses.COLS / 9)
98+ p3.set_userptr("p3")
99+
100+ p4 = mkpanel(curses.COLOR_BLUE,
101+ curses.LINES / 2 - 2,
102+ curses.COLS / 8,
103+ curses.LINES / 2 - 2,
104+ curses.COLS / 3)
105+ p4.set_userptr("p4")
106+
107+ p5 = mkpanel(curses.COLOR_MAGENTA,
108+ curses.LINES / 2 - 2,
109+ curses.COLS / 8,
110+ curses.LINES / 2,
111+ curses.COLS / 2 - 2)
112+ p5.set_userptr("p5")
113+
114+ fill_panel(p1)
115+ fill_panel(p2)
116+ fill_panel(p3)
117+ fill_panel(p4)
118+ fill_panel(p5)
119+ p4.hide()
120+ p5.hide()
121+ pflush()
122+ saywhat("press any key to continue")
123+ wait_a_while()
124+
125+ saywhat("h3 s1 s2 s4 s5;press any key to continue")
126+ p1.move(0, 0)
127+ p3.hide()
128+ p1.show()
129+ p2.show()
130+ p4.show()
131+ p5.show()
132+ pflush()
133+ wait_a_while()
134+
135+ saywhat("s1; press any key to continue")
136+ p1.show()
137+ pflush()
138+ wait_a_while()
139+
140+ saywhat("s2; press any key to continue")
141+ p2.show()
142+ pflush()
143+ wait_a_while()
144+
145+ saywhat("m2; press any key to continue")
146+ p2.move(curses.LINES / 3 + 1, curses.COLS / 8)
147+ pflush()
148+ wait_a_while()
149+
150+ saywhat("s3; press any key to continue")
151+ p3.show()
152+ pflush()
153+ wait_a_while()
154+
155+ saywhat("m3; press any key to continue")
156+ p3.move(curses.LINES / 4 + 1, curses.COLS / 15)
157+ pflush()
158+ wait_a_while()
159+
160+ saywhat("b3; press any key to continue")
161+ p3.bottom()
162+ pflush()
163+ wait_a_while()
164+
165+ saywhat("s4; press any key to continue")
166+ p4.show()
167+ pflush()
168+ wait_a_while()
169+
170+ saywhat("s5; press any key to continue")
171+ p5.show()
172+ pflush()
173+ wait_a_while()
174+
175+ saywhat("t3; press any key to continue")
176+ p3.top()
177+ pflush()
178+ wait_a_while()
179+
180+ saywhat("t1; press any key to continue")
181+ p1.show()
182+ pflush()
183+ wait_a_while()
184+
185+ saywhat("t2; press any key to continue")
186+ p2.show()
187+ pflush()
188+ wait_a_while()
189+
190+ saywhat("t3; press any key to continue")
191+ p3.show()
192+ pflush()
193+ wait_a_while()
194+
195+ saywhat("t4; press any key to continue")
196+ p4.show()
197+ pflush()
198+ wait_a_while()
199+
200+ for itmp in range(0, 6):
201+ w4 = p4.window()
202+ w5 = p5.window()
203+
204+ saywhat("m4; press any key to continue")
205+ w4.move(curses.LINES / 8, 1)
206+ w4.addstr(mod[itmp])
207+ p4.move(curses.LINES / 6, itmp * curses.COLS / 8)
208+ w5.move(curses.LINES / 6, 1)
209+ w5.addstr(mod[itmp])
210+ pflush()
211+ wait_a_while()
212+
213+ saywhat("m5; press any key to continue")
214+ w4.move(curses.LINES / 6, 1)
215+ w4.addstr(mod[itmp])
216+ p5.move(curses.LINES / 3 - 1, itmp * 10 + 6)
217+ w5.move(curses.LINES / 8, 1)
218+ w5.addstr(mod[itmp])
219+ pflush()
220+ wait_a_while()
221+
222+ saywhat("m4; press any key to continue")
223+ p4.move(curses.LINES / 6, (itmp + 1) * curses.COLS / 8)
224+ pflush()
225+ wait_a_while()
226+
227+ saywhat("t5; press any key to continue")
228+ p5.top()
229+ pflush()
230+ wait_a_while()
231+
232+ saywhat("t2; press any key to continue")
233+ p2.top()
234+ pflush()
235+ wait_a_while()
236+
237+ saywhat("t1; press any key to continue")
238+ p1.top()
239+ pflush()
240+ wait_a_while()
241+
242+ saywhat("d2; press any key to continue")
243+ del p2
244+ pflush()
245+ wait_a_while()
246+
247+ saywhat("h3; press any key to continue")
248+ p3.hide()
249+ pflush()
250+ wait_a_while()
251+
252+ saywhat("d1; press any key to continue")
253+ del p1
254+ pflush()
255+ wait_a_while()
256+
257+ saywhat("d4; press any key to continue")
258+ del p4
259+ pflush()
260+ wait_a_while()
261+
262+ saywhat("d5; press any key to continue")
263+ del p5
264+ pflush()
265+ wait_a_while()
266+ if nap_msec == 1:
267+ break
268+ nap_msec = 100
269+
270+#
271+# one fine day there'll be the menu at this place
272+#
273+curses.wrapper(demo_panels)
sys/src/cmd/python/Demo/curses/rain.py+94−0
@@ -0,0 +1,94 @@
1+#!/bin/python
2+#
3+# $Id: rain.py 46625 2006-06-03 23:02:15Z andrew.kuchling $
4+#
5+# somebody should probably check the randrange()s...
6+
7+import curses
8+from random import randrange
9+
10+def next_j(j):
11+ if j == 0:
12+ j = 4
13+ else:
14+ j -= 1
15+
16+ if curses.has_colors():
17+ z = randrange(0, 3)
18+ color = curses.color_pair(z)
19+ if z:
20+ color = color | curses.A_BOLD
21+ stdscr.attrset(color)
22+
23+ return j
24+
25+def main(win):
26+ # we know that the first argument from curses.wrapper() is stdscr.
27+ # Initialize it globally for convenience.
28+ global stdscr
29+ stdscr = win
30+
31+ if curses.has_colors():
32+ bg = curses.COLOR_BLACK
33+ curses.init_pair(1, curses.COLOR_BLUE, bg)
34+ curses.init_pair(2, curses.COLOR_CYAN, bg)
35+
36+ curses.nl()
37+ curses.noecho()
38+ # XXX curs_set() always returns ERR
39+ # curses.curs_set(0)
40+ stdscr.timeout(0)
41+
42+ c = curses.COLS - 4
43+ r = curses.LINES - 4
44+ xpos = [0] * c
45+ ypos = [0] * r
46+ for j in range(4, -1, -1):
47+ xpos[j] = randrange(0, c) + 2
48+ ypos[j] = randrange(0, r) + 2
49+
50+ j = 0
51+ while True:
52+ x = randrange(0, c) + 2
53+ y = randrange(0, r) + 2
54+
55+ stdscr.addch(y, x, ord('.'))
56+
57+ stdscr.addch(ypos[j], xpos[j], ord('o'))
58+
59+ j = next_j(j)
60+ stdscr.addch(ypos[j], xpos[j], ord('O'))
61+
62+ j = next_j(j)
63+ stdscr.addch( ypos[j] - 1, xpos[j], ord('-'))
64+ stdscr.addstr(ypos[j], xpos[j] - 1, "|.|")
65+ stdscr.addch( ypos[j] + 1, xpos[j], ord('-'))
66+
67+ j = next_j(j)
68+ stdscr.addch( ypos[j] - 2, xpos[j], ord('-'))
69+ stdscr.addstr(ypos[j] - 1, xpos[j] - 1, "/ \\")
70+ stdscr.addstr(ypos[j], xpos[j] - 2, "| O |")
71+ stdscr.addstr(ypos[j] + 1, xpos[j] - 1, "\\ /")
72+ stdscr.addch( ypos[j] + 2, xpos[j], ord('-'))
73+
74+ j = next_j(j)
75+ stdscr.addch( ypos[j] - 2, xpos[j], ord(' '))
76+ stdscr.addstr(ypos[j] - 1, xpos[j] - 1, " ")
77+ stdscr.addstr(ypos[j], xpos[j] - 2, " ")
78+ stdscr.addstr(ypos[j] + 1, xpos[j] - 1, " ")
79+ stdscr.addch( ypos[j] + 2, xpos[j], ord(' '))
80+
81+ xpos[j] = x
82+ ypos[j] = y
83+
84+ ch = stdscr.getch()
85+ if ch == ord('q') or ch == ord('Q'):
86+ return
87+ elif ch == ord('s'):
88+ stdscr.nodelay(0)
89+ elif ch == ord(' '):
90+ stdscr.nodelay(1)
91+
92+ curses.napms(50)
93+
94+curses.wrapper(main)
sys/src/cmd/python/Demo/curses/repeat.py+58−0
@@ -0,0 +1,58 @@
1+#! /usr/bin/env python
2+
3+"""repeat <shell-command>
4+
5+This simple program repeatedly (at 1-second intervals) executes the
6+shell command given on the command line and displays the output (or as
7+much of it as fits on the screen). It uses curses to paint each new
8+output on top of the old output, so that if nothing changes, the
9+screen doesn't change. This is handy to watch for changes in e.g. a
10+directory or process listing.
11+
12+To end, hit Control-C.
13+"""
14+
15+# Author: Guido van Rossum
16+
17+# Disclaimer: there's a Linux program named 'watch' that does the same
18+# thing. Honestly, I didn't know of its existence when I wrote this!
19+
20+# To do: add features until it has the same functionality as watch(1);
21+# then compare code size and development time.
22+
23+import os
24+import sys
25+import time
26+import curses
27+
28+def main():
29+ if not sys.argv[1:]:
30+ print __doc__
31+ sys.exit(0)
32+ cmd = " ".join(sys.argv[1:])
33+ p = os.popen(cmd, "r")
34+ text = p.read()
35+ sts = p.close()
36+ if sts:
37+ print >>sys.stderr, "Exit code:", sts
38+ sys.exit(sts)
39+ w = curses.initscr()
40+ try:
41+ while True:
42+ w.erase()
43+ try:
44+ w.addstr(text)
45+ except curses.error:
46+ pass
47+ w.refresh()
48+ time.sleep(1)
49+ p = os.popen(cmd, "r")
50+ text = p.read()
51+ sts = p.close()
52+ if sts:
53+ print >>sys.stderr, "Exit code:", sts
54+ sys.exit(sts)
55+ finally:
56+ curses.endwin()
57+
58+main()
sys/src/cmd/python/Demo/curses/tclock.py+147−0
@@ -0,0 +1,147 @@
1+#!/usr/bin/env python
2+#
3+# $Id: tclock.py 46626 2006-06-03 23:07:21Z andrew.kuchling $
4+#
5+# From tclock.c, Copyright Howard Jones <ha.jones@ic.ac.uk>, September 1994.
6+
7+from math import *
8+import curses, time
9+
10+ASPECT = 2.2
11+
12+def sign(_x):
13+ if _x < 0: return -1
14+ return 1
15+
16+def A2XY(angle, radius):
17+ return (int(round(ASPECT * radius * sin(angle))),
18+ int(round(radius * cos(angle))))
19+
20+def plot(x, y, col):
21+ stdscr.addch(y, x, col)
22+
23+# draw a diagonal line using Bresenham's algorithm
24+def dline(pair, from_x, from_y, x2, y2, ch):
25+ if curses.has_colors():
26+ stdscr.attrset(curses.color_pair(pair))
27+
28+ dx = x2 - from_x
29+ dy = y2 - from_y
30+
31+ ax = abs(dx * 2)
32+ ay = abs(dy * 2)
33+
34+ sx = sign(dx)
35+ sy = sign(dy)
36+
37+ x = from_x
38+ y = from_y
39+
40+ if ax > ay:
41+ d = ay - ax // 2
42+
43+ while True:
44+ plot(x, y, ch)
45+ if x == x2:
46+ return
47+
48+ if d >= 0:
49+ y += sy
50+ d -= ax
51+ x += sx
52+ d += ay
53+ else:
54+ d = ax - ay // 2
55+
56+ while True:
57+ plot(x, y, ch)
58+ if y == y2:
59+ return
60+
61+ if d >= 0:
62+ x += sx
63+ d -= ay
64+ y += sy
65+ d += ax
66+
67+def main(win):
68+ global stdscr
69+ stdscr = win
70+
71+ lastbeep = -1
72+ my_bg = curses.COLOR_BLACK
73+
74+ stdscr.nodelay(1)
75+ stdscr.timeout(0)
76+# curses.curs_set(0)
77+ if curses.has_colors():
78+ curses.init_pair(1, curses.COLOR_RED, my_bg)
79+ curses.init_pair(2, curses.COLOR_MAGENTA, my_bg)
80+ curses.init_pair(3, curses.COLOR_GREEN, my_bg)
81+
82+ cx = (curses.COLS - 1) // 2
83+ cy = curses.LINES // 2
84+ ch = min( cy-1, int(cx // ASPECT) - 1)
85+ mradius = (3 * ch) // 4
86+ hradius = ch // 2
87+ sradius = 5 * ch // 6
88+
89+ for i in range(0, 12):
90+ sangle = (i + 1) * 2.0 * pi / 12.0
91+ sdx, sdy = A2XY(sangle, sradius)
92+
93+ stdscr.addstr(cy - sdy, cx + sdx, "%d" % (i + 1))
94+
95+ stdscr.addstr(0, 0,
96+ "ASCII Clock by Howard Jones <ha.jones@ic.ac.uk>, 1994")
97+
98+ sradius = max(sradius-4, 8)
99+
100+ while True:
101+ curses.napms(1000)
102+
103+ tim = time.time()
104+ t = time.localtime(tim)
105+
106+ hours = t[3] + t[4] / 60.0
107+ if hours > 12.0:
108+ hours -= 12.0
109+
110+ mangle = t[4] * 2 * pi / 60.0
111+ mdx, mdy = A2XY(mangle, mradius)
112+
113+ hangle = hours * 2 * pi / 12.0
114+ hdx, hdy = A2XY(hangle, hradius)
115+
116+ sangle = t[5] * 2 * pi / 60.0
117+ sdx, sdy = A2XY(sangle, sradius)
118+
119+ dline(3, cx, cy, cx + mdx, cy - mdy, ord('#'))
120+
121+ stdscr.attrset(curses.A_REVERSE)
122+ dline(2, cx, cy, cx + hdx, cy - hdy, ord('.'))
123+ stdscr.attroff(curses.A_REVERSE)
124+
125+ if curses.has_colors():
126+ stdscr.attrset(curses.color_pair(1))
127+
128+ plot(cx + sdx, cy - sdy, ord('O'))
129+
130+ if curses.has_colors():
131+ stdscr.attrset(curses.color_pair(0))
132+
133+ stdscr.addstr(curses.LINES - 2, 0, time.ctime(tim))
134+ stdscr.refresh()
135+ if (t[5] % 5) == 0 and t[5] != lastbeep:
136+ lastbeep = t[5]
137+ curses.beep()
138+
139+ ch = stdscr.getch()
140+ if ch == ord('q'):
141+ return 0
142+
143+ plot(cx + sdx, cy - sdy, ord(' '))
144+ dline(0, cx, cy, cx + hdx, cy - hdy, ord(' '))
145+ dline(0, cx, cy, cx + mdx, cy - mdy, ord(' '))
146+
147+curses.wrapper(main)
sys/src/cmd/python/Demo/curses/xmas.py+906−0
@@ -0,0 +1,906 @@
1+# asciixmas
2+# December 1989 Larry Bartz Indianapolis, IN
3+#
4+# $Id: xmas.py 46623 2006-06-03 22:59:23Z andrew.kuchling $
5+#
6+# I'm dreaming of an ascii character-based monochrome Christmas,
7+# Just like the ones I used to know!
8+# Via a full duplex communications channel,
9+# At 9600 bits per second,
10+# Even though it's kinda slow.
11+#
12+# I'm dreaming of an ascii character-based monochrome Christmas,
13+# With ev'ry C program I write!
14+# May your screen be merry and bright!
15+# And may all your Christmases be amber or green,
16+# (for reduced eyestrain and improved visibility)!
17+#
18+#
19+# Notes on the Python version:
20+# I used a couple of `try...except curses.error' to get around some functions
21+# returning ERR. The errors come from using wrapping functions to fill
22+# windows to the last character cell. The C version doesn't have this problem,
23+# it simply ignores any return values.
24+#
25+
26+import curses
27+import sys
28+
29+FROMWHO = "Thomas Gellekum <tg@FreeBSD.org>"
30+
31+def set_color(win, color):
32+ if curses.has_colors():
33+ n = color + 1
34+ curses.init_pair(n, color, my_bg)
35+ win.attroff(curses.A_COLOR)
36+ win.attron(curses.color_pair(n))
37+
38+def unset_color(win):
39+ if curses.has_colors():
40+ win.attrset(curses.color_pair(0))
41+
42+def look_out(msecs):
43+ curses.napms(msecs)
44+ if stdscr.getch() != -1:
45+ curses.beep()
46+ sys.exit(0)
47+
48+def boxit():
49+ for y in range(0, 20):
50+ stdscr.addch(y, 7, ord('|'))
51+
52+ for x in range(8, 80):
53+ stdscr.addch(19, x, ord('_'))
54+
55+ for x in range(0, 80):
56+ stdscr.addch(22, x, ord('_'))
57+
58+ return
59+
60+def seas():
61+ stdscr.addch(4, 1, ord('S'))
62+ stdscr.addch(6, 1, ord('E'))
63+ stdscr.addch(8, 1, ord('A'))
64+ stdscr.addch(10, 1, ord('S'))
65+ stdscr.addch(12, 1, ord('O'))
66+ stdscr.addch(14, 1, ord('N'))
67+ stdscr.addch(16, 1, ord("'"))
68+ stdscr.addch(18, 1, ord('S'))
69+
70+ return
71+
72+def greet():
73+ stdscr.addch(3, 5, ord('G'))
74+ stdscr.addch(5, 5, ord('R'))
75+ stdscr.addch(7, 5, ord('E'))
76+ stdscr.addch(9, 5, ord('E'))
77+ stdscr.addch(11, 5, ord('T'))
78+ stdscr.addch(13, 5, ord('I'))
79+ stdscr.addch(15, 5, ord('N'))
80+ stdscr.addch(17, 5, ord('G'))
81+ stdscr.addch(19, 5, ord('S'))
82+
83+ return
84+
85+def fromwho():
86+ stdscr.addstr(21, 13, FROMWHO)
87+ return
88+
89+def tree():
90+ set_color(treescrn, curses.COLOR_GREEN)
91+ treescrn.addch(1, 11, ord('/'))
92+ treescrn.addch(2, 11, ord('/'))
93+ treescrn.addch(3, 10, ord('/'))
94+ treescrn.addch(4, 9, ord('/'))
95+ treescrn.addch(5, 9, ord('/'))
96+ treescrn.addch(6, 8, ord('/'))
97+ treescrn.addch(7, 7, ord('/'))
98+ treescrn.addch(8, 6, ord('/'))
99+ treescrn.addch(9, 6, ord('/'))
100+ treescrn.addch(10, 5, ord('/'))
101+ treescrn.addch(11, 3, ord('/'))
102+ treescrn.addch(12, 2, ord('/'))
103+
104+ treescrn.addch(1, 13, ord('\\'))
105+ treescrn.addch(2, 13, ord('\\'))
106+ treescrn.addch(3, 14, ord('\\'))
107+ treescrn.addch(4, 15, ord('\\'))
108+ treescrn.addch(5, 15, ord('\\'))
109+ treescrn.addch(6, 16, ord('\\'))
110+ treescrn.addch(7, 17, ord('\\'))
111+ treescrn.addch(8, 18, ord('\\'))
112+ treescrn.addch(9, 18, ord('\\'))
113+ treescrn.addch(10, 19, ord('\\'))
114+ treescrn.addch(11, 21, ord('\\'))
115+ treescrn.addch(12, 22, ord('\\'))
116+
117+ treescrn.addch(4, 10, ord('_'))
118+ treescrn.addch(4, 14, ord('_'))
119+ treescrn.addch(8, 7, ord('_'))
120+ treescrn.addch(8, 17, ord('_'))
121+
122+ treescrn.addstr(13, 0, "//////////// \\\\\\\\\\\\\\\\\\\\\\\\")
123+
124+ treescrn.addstr(14, 11, "| |")
125+ treescrn.addstr(15, 11, "|_|")
126+
127+ unset_color(treescrn)
128+ treescrn.refresh()
129+ w_del_msg.refresh()
130+
131+ return
132+
133+def balls():
134+ treescrn.overlay(treescrn2)
135+
136+ set_color(treescrn2, curses.COLOR_BLUE)
137+ treescrn2.addch(3, 9, ord('@'))
138+ treescrn2.addch(3, 15, ord('@'))
139+ treescrn2.addch(4, 8, ord('@'))
140+ treescrn2.addch(4, 16, ord('@'))
141+ treescrn2.addch(5, 7, ord('@'))
142+ treescrn2.addch(5, 17, ord('@'))
143+ treescrn2.addch(7, 6, ord('@'))
144+ treescrn2.addch(7, 18, ord('@'))
145+ treescrn2.addch(8, 5, ord('@'))
146+ treescrn2.addch(8, 19, ord('@'))
147+ treescrn2.addch(10, 4, ord('@'))
148+ treescrn2.addch(10, 20, ord('@'))
149+ treescrn2.addch(11, 2, ord('@'))
150+ treescrn2.addch(11, 22, ord('@'))
151+ treescrn2.addch(12, 1, ord('@'))
152+ treescrn2.addch(12, 23, ord('@'))
153+
154+ unset_color(treescrn2)
155+ treescrn2.refresh()
156+ w_del_msg.refresh()
157+ return
158+
159+def star():
160+ treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
161+ set_color(treescrn2, curses.COLOR_YELLOW)
162+
163+ treescrn2.addch(0, 12, ord('*'))
164+ treescrn2.standend()
165+
166+ unset_color(treescrn2)
167+ treescrn2.refresh()
168+ w_del_msg.refresh()
169+ return
170+
171+def strng1():
172+ treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
173+ set_color(treescrn2, curses.COLOR_WHITE)
174+
175+ treescrn2.addch(3, 13, ord('\''))
176+ treescrn2.addch(3, 12, ord(':'))
177+ treescrn2.addch(3, 11, ord('.'))
178+
179+ treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
180+ unset_color(treescrn2)
181+
182+ treescrn2.refresh()
183+ w_del_msg.refresh()
184+ return
185+
186+def strng2():
187+ treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
188+ set_color(treescrn2, curses.COLOR_WHITE)
189+
190+ treescrn2.addch(5, 14, ord('\''))
191+ treescrn2.addch(5, 13, ord(':'))
192+ treescrn2.addch(5, 12, ord('.'))
193+ treescrn2.addch(5, 11, ord(','))
194+ treescrn2.addch(6, 10, ord('\''))
195+ treescrn2.addch(6, 9, ord(':'))
196+
197+ treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
198+ unset_color(treescrn2)
199+
200+ treescrn2.refresh()
201+ w_del_msg.refresh()
202+ return
203+
204+def strng3():
205+ treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
206+ set_color(treescrn2, curses.COLOR_WHITE)
207+
208+ treescrn2.addch(7, 16, ord('\''))
209+ treescrn2.addch(7, 15, ord(':'))
210+ treescrn2.addch(7, 14, ord('.'))
211+ treescrn2.addch(7, 13, ord(','))
212+ treescrn2.addch(8, 12, ord('\''))
213+ treescrn2.addch(8, 11, ord(':'))
214+ treescrn2.addch(8, 10, ord('.'))
215+ treescrn2.addch(8, 9, ord(','))
216+
217+ treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
218+ unset_color(treescrn2)
219+
220+ treescrn2.refresh()
221+ w_del_msg.refresh()
222+ return
223+
224+def strng4():
225+ treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
226+ set_color(treescrn2, curses.COLOR_WHITE)
227+
228+ treescrn2.addch(9, 17, ord('\''))
229+ treescrn2.addch(9, 16, ord(':'))
230+ treescrn2.addch(9, 15, ord('.'))
231+ treescrn2.addch(9, 14, ord(','))
232+ treescrn2.addch(10, 13, ord('\''))
233+ treescrn2.addch(10, 12, ord(':'))
234+ treescrn2.addch(10, 11, ord('.'))
235+ treescrn2.addch(10, 10, ord(','))
236+ treescrn2.addch(11, 9, ord('\''))
237+ treescrn2.addch(11, 8, ord(':'))
238+ treescrn2.addch(11, 7, ord('.'))
239+ treescrn2.addch(11, 6, ord(','))
240+ treescrn2.addch(12, 5, ord('\''))
241+
242+ treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
243+ unset_color(treescrn2)
244+
245+ treescrn2.refresh()
246+ w_del_msg.refresh()
247+ return
248+
249+def strng5():
250+ treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
251+ set_color(treescrn2, curses.COLOR_WHITE)
252+
253+ treescrn2.addch(11, 19, ord('\''))
254+ treescrn2.addch(11, 18, ord(':'))
255+ treescrn2.addch(11, 17, ord('.'))
256+ treescrn2.addch(11, 16, ord(','))
257+ treescrn2.addch(12, 15, ord('\''))
258+ treescrn2.addch(12, 14, ord(':'))
259+ treescrn2.addch(12, 13, ord('.'))
260+ treescrn2.addch(12, 12, ord(','))
261+
262+ treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
263+ unset_color(treescrn2)
264+
265+ # save a fully lit tree
266+ treescrn2.overlay(treescrn)
267+
268+ treescrn2.refresh()
269+ w_del_msg.refresh()
270+ return
271+
272+def blinkit():
273+ treescrn8.touchwin()
274+
275+ for cycle in range(5):
276+ if cycle == 0:
277+ treescrn3.overlay(treescrn8)
278+ treescrn8.refresh()
279+ w_del_msg.refresh()
280+ break
281+ elif cycle == 1:
282+ treescrn4.overlay(treescrn8)
283+ treescrn8.refresh()
284+ w_del_msg.refresh()
285+ break
286+ elif cycle == 2:
287+ treescrn5.overlay(treescrn8)
288+ treescrn8.refresh()
289+ w_del_msg.refresh()
290+ break
291+ elif cycle == 3:
292+ treescrn6.overlay(treescrn8)
293+ treescrn8.refresh()
294+ w_del_msg.refresh()
295+ break
296+ elif cycle == 4:
297+ treescrn7.overlay(treescrn8)
298+ treescrn8.refresh()
299+ w_del_msg.refresh()
300+ break
301+
302+ treescrn8.touchwin()
303+
304+ # ALL ON
305+ treescrn.overlay(treescrn8)
306+ treescrn8.refresh()
307+ w_del_msg.refresh()
308+
309+ return
310+
311+def deer_step(win, y, x):
312+ win.mvwin(y, x)
313+ win.refresh()
314+ w_del_msg.refresh()
315+ look_out(5)
316+
317+def reindeer():
318+ y_pos = 0
319+
320+ for x_pos in range(70, 62, -1):
321+ if x_pos < 66: y_pos = 1
322+ for looper in range(0, 4):
323+ dotdeer0.addch(y_pos, x_pos, ord('.'))
324+ dotdeer0.refresh()
325+ w_del_msg.refresh()
326+ dotdeer0.erase()
327+ dotdeer0.refresh()
328+ w_del_msg.refresh()
329+ look_out(50)
330+
331+ y_pos = 2
332+
333+ for x_pos in range(x_pos - 1, 50, -1):
334+ for looper in range(0, 4):
335+ if x_pos < 56:
336+ y_pos = 3
337+
338+ try:
339+ stardeer0.addch(y_pos, x_pos, ord('*'))
340+ except curses.error:
341+ pass
342+ stardeer0.refresh()
343+ w_del_msg.refresh()
344+ stardeer0.erase()
345+ stardeer0.refresh()
346+ w_del_msg.refresh()
347+ else:
348+ dotdeer0.addch(y_pos, x_pos, ord('*'))
349+ dotdeer0.refresh()
350+ w_del_msg.refresh()
351+ dotdeer0.erase()
352+ dotdeer0.refresh()
353+ w_del_msg.refresh()
354+
355+ x_pos = 58
356+
357+ for y_pos in range(2, 5):
358+ lildeer0.touchwin()
359+ lildeer0.refresh()
360+ w_del_msg.refresh()
361+
362+ for looper in range(0, 4):
363+ deer_step(lildeer3, y_pos, x_pos)
364+ deer_step(lildeer2, y_pos, x_pos)
365+ deer_step(lildeer1, y_pos, x_pos)
366+ deer_step(lildeer2, y_pos, x_pos)
367+ deer_step(lildeer3, y_pos, x_pos)
368+
369+ lildeer0.touchwin()
370+ lildeer0.refresh()
371+ w_del_msg.refresh()
372+
373+ x_pos -= 2
374+
375+ x_pos = 35
376+
377+ for y_pos in range(5, 10):
378+
379+ middeer0.touchwin()
380+ middeer0.refresh()
381+ w_del_msg.refresh()
382+
383+ for looper in range(2):
384+ deer_step(middeer3, y_pos, x_pos)
385+ deer_step(middeer2, y_pos, x_pos)
386+ deer_step(middeer1, y_pos, x_pos)
387+ deer_step(middeer2, y_pos, x_pos)
388+ deer_step(middeer3, y_pos, x_pos)
389+
390+ middeer0.touchwin()
391+ middeer0.refresh()
392+ w_del_msg.refresh()
393+
394+ x_pos -= 3
395+
396+ look_out(300)
397+
398+ y_pos = 1
399+
400+ for x_pos in range(8, 16):
401+ deer_step(bigdeer4, y_pos, x_pos)
402+ deer_step(bigdeer3, y_pos, x_pos)
403+ deer_step(bigdeer2, y_pos, x_pos)
404+ deer_step(bigdeer1, y_pos, x_pos)
405+ deer_step(bigdeer2, y_pos, x_pos)
406+ deer_step(bigdeer3, y_pos, x_pos)
407+ deer_step(bigdeer4, y_pos, x_pos)
408+ deer_step(bigdeer0, y_pos, x_pos)
409+
410+ x_pos -= 1
411+
412+ for looper in range(0, 6):
413+ deer_step(lookdeer4, y_pos, x_pos)
414+ deer_step(lookdeer3, y_pos, x_pos)
415+ deer_step(lookdeer2, y_pos, x_pos)
416+ deer_step(lookdeer1, y_pos, x_pos)
417+ deer_step(lookdeer2, y_pos, x_pos)
418+ deer_step(lookdeer3, y_pos, x_pos)
419+ deer_step(lookdeer4, y_pos, x_pos)
420+
421+ deer_step(lookdeer0, y_pos, x_pos)
422+
423+ for y_pos in range(y_pos, 10):
424+ for looper in range(0, 2):
425+ deer_step(bigdeer4, y_pos, x_pos)
426+ deer_step(bigdeer3, y_pos, x_pos)
427+ deer_step(bigdeer2, y_pos, x_pos)
428+ deer_step(bigdeer1, y_pos, x_pos)
429+ deer_step(bigdeer2, y_pos, x_pos)
430+ deer_step(bigdeer3, y_pos, x_pos)
431+ deer_step(bigdeer4, y_pos, x_pos)
432+ deer_step(bigdeer0, y_pos, x_pos)
433+
434+ y_pos -= 1
435+
436+ deer_step(lookdeer3, y_pos, x_pos)
437+ return
438+
439+def main(win):
440+ global stdscr
441+ stdscr = win
442+
443+ global my_bg, y_pos, x_pos
444+ global treescrn, treescrn2, treescrn3, treescrn4
445+ global treescrn5, treescrn6, treescrn7, treescrn8
446+ global dotdeer0, stardeer0
447+ global lildeer0, lildeer1, lildeer2, lildeer3
448+ global middeer0, middeer1, middeer2, middeer3
449+ global bigdeer0, bigdeer1, bigdeer2, bigdeer3, bigdeer4
450+ global lookdeer0, lookdeer1, lookdeer2, lookdeer3, lookdeer4
451+ global w_holiday, w_del_msg
452+
453+ my_bg = curses.COLOR_BLACK
454+ # curses.curs_set(0)
455+
456+ treescrn = curses.newwin(16, 27, 3, 53)
457+ treescrn2 = curses.newwin(16, 27, 3, 53)
458+ treescrn3 = curses.newwin(16, 27, 3, 53)
459+ treescrn4 = curses.newwin(16, 27, 3, 53)
460+ treescrn5 = curses.newwin(16, 27, 3, 53)
461+ treescrn6 = curses.newwin(16, 27, 3, 53)
462+ treescrn7 = curses.newwin(16, 27, 3, 53)
463+ treescrn8 = curses.newwin(16, 27, 3, 53)
464+
465+ dotdeer0 = curses.newwin(3, 71, 0, 8)
466+
467+ stardeer0 = curses.newwin(4, 56, 0, 8)
468+
469+ lildeer0 = curses.newwin(7, 53, 0, 8)
470+ lildeer1 = curses.newwin(2, 4, 0, 0)
471+ lildeer2 = curses.newwin(2, 4, 0, 0)
472+ lildeer3 = curses.newwin(2, 4, 0, 0)
473+
474+ middeer0 = curses.newwin(15, 42, 0, 8)
475+ middeer1 = curses.newwin(3, 7, 0, 0)
476+ middeer2 = curses.newwin(3, 7, 0, 0)
477+ middeer3 = curses.newwin(3, 7, 0, 0)
478+
479+ bigdeer0 = curses.newwin(10, 23, 0, 0)
480+ bigdeer1 = curses.newwin(10, 23, 0, 0)
481+ bigdeer2 = curses.newwin(10, 23, 0, 0)
482+ bigdeer3 = curses.newwin(10, 23, 0, 0)
483+ bigdeer4 = curses.newwin(10, 23, 0, 0)
484+
485+ lookdeer0 = curses.newwin(10, 25, 0, 0)
486+ lookdeer1 = curses.newwin(10, 25, 0, 0)
487+ lookdeer2 = curses.newwin(10, 25, 0, 0)
488+ lookdeer3 = curses.newwin(10, 25, 0, 0)
489+ lookdeer4 = curses.newwin(10, 25, 0, 0)
490+
491+ w_holiday = curses.newwin(1, 27, 3, 27)
492+
493+ w_del_msg = curses.newwin(1, 20, 23, 60)
494+
495+ try:
496+ w_del_msg.addstr(0, 0, "Hit any key to quit")
497+ except curses.error:
498+ pass
499+
500+ try:
501+ w_holiday.addstr(0, 0, "H A P P Y H O L I D A Y S")
502+ except curses.error:
503+ pass
504+
505+ # set up the windows for our various reindeer
506+ lildeer1.addch(0, 0, ord('V'))
507+ lildeer1.addch(1, 0, ord('@'))
508+ lildeer1.addch(1, 1, ord('<'))
509+ lildeer1.addch(1, 2, ord('>'))
510+ try:
511+ lildeer1.addch(1, 3, ord('~'))
512+ except curses.error:
513+ pass
514+
515+ lildeer2.addch(0, 0, ord('V'))
516+ lildeer2.addch(1, 0, ord('@'))
517+ lildeer2.addch(1, 1, ord('|'))
518+ lildeer2.addch(1, 2, ord('|'))
519+ try:
520+ lildeer2.addch(1, 3, ord('~'))
521+ except curses.error:
522+ pass
523+
524+ lildeer3.addch(0, 0, ord('V'))
525+ lildeer3.addch(1, 0, ord('@'))
526+ lildeer3.addch(1, 1, ord('>'))
527+ lildeer3.addch(1, 2, ord('<'))
528+ try:
529+ lildeer2.addch(1, 3, ord('~')) # XXX
530+ except curses.error:
531+ pass
532+
533+ middeer1.addch(0, 2, ord('y'))
534+ middeer1.addch(0, 3, ord('y'))
535+ middeer1.addch(1, 2, ord('0'))
536+ middeer1.addch(1, 3, ord('('))
537+ middeer1.addch(1, 4, ord('='))
538+ middeer1.addch(1, 5, ord(')'))
539+ middeer1.addch(1, 6, ord('~'))
540+ middeer1.addch(2, 3, ord('\\'))
541+ middeer1.addch(2, 5, ord('/'))
542+
543+ middeer2.addch(0, 2, ord('y'))
544+ middeer2.addch(0, 3, ord('y'))
545+ middeer2.addch(1, 2, ord('0'))
546+ middeer2.addch(1, 3, ord('('))
547+ middeer2.addch(1, 4, ord('='))
548+ middeer2.addch(1, 5, ord(')'))
549+ middeer2.addch(1, 6, ord('~'))
550+ middeer2.addch(2, 3, ord('|'))
551+ middeer2.addch(2, 5, ord('|'))
552+
553+ middeer3.addch(0, 2, ord('y'))
554+ middeer3.addch(0, 3, ord('y'))
555+ middeer3.addch(1, 2, ord('0'))
556+ middeer3.addch(1, 3, ord('('))
557+ middeer3.addch(1, 4, ord('='))
558+ middeer3.addch(1, 5, ord(')'))
559+ middeer3.addch(1, 6, ord('~'))
560+ middeer3.addch(2, 3, ord('/'))
561+ middeer3.addch(2, 5, ord('\\'))
562+
563+ bigdeer1.addch(0, 17, ord('\\'))
564+ bigdeer1.addch(0, 18, ord('/'))
565+ bigdeer1.addch(0, 19, ord('\\'))
566+ bigdeer1.addch(0, 20, ord('/'))
567+ bigdeer1.addch(1, 18, ord('\\'))
568+ bigdeer1.addch(1, 20, ord('/'))
569+ bigdeer1.addch(2, 19, ord('|'))
570+ bigdeer1.addch(2, 20, ord('_'))
571+ bigdeer1.addch(3, 18, ord('/'))
572+ bigdeer1.addch(3, 19, ord('^'))
573+ bigdeer1.addch(3, 20, ord('0'))
574+ bigdeer1.addch(3, 21, ord('\\'))
575+ bigdeer1.addch(4, 17, ord('/'))
576+ bigdeer1.addch(4, 18, ord('/'))
577+ bigdeer1.addch(4, 19, ord('\\'))
578+ bigdeer1.addch(4, 22, ord('\\'))
579+ bigdeer1.addstr(5, 7, "^~~~~~~~~// ~~U")
580+ bigdeer1.addstr(6, 7, "( \\_____( /") # ))
581+ bigdeer1.addstr(7, 8, "( ) /")
582+ bigdeer1.addstr(8, 9, "\\\\ /")
583+ bigdeer1.addstr(9, 11, "\\>/>")
584+
585+ bigdeer2.addch(0, 17, ord('\\'))
586+ bigdeer2.addch(0, 18, ord('/'))
587+ bigdeer2.addch(0, 19, ord('\\'))
588+ bigdeer2.addch(0, 20, ord('/'))
589+ bigdeer2.addch(1, 18, ord('\\'))
590+ bigdeer2.addch(1, 20, ord('/'))
591+ bigdeer2.addch(2, 19, ord('|'))
592+ bigdeer2.addch(2, 20, ord('_'))
593+ bigdeer2.addch(3, 18, ord('/'))
594+ bigdeer2.addch(3, 19, ord('^'))
595+ bigdeer2.addch(3, 20, ord('0'))
596+ bigdeer2.addch(3, 21, ord('\\'))
597+ bigdeer2.addch(4, 17, ord('/'))
598+ bigdeer2.addch(4, 18, ord('/'))
599+ bigdeer2.addch(4, 19, ord('\\'))
600+ bigdeer2.addch(4, 22, ord('\\'))
601+ bigdeer2.addstr(5, 7, "^~~~~~~~~// ~~U")
602+ bigdeer2.addstr(6, 7, "(( )____( /") # ))
603+ bigdeer2.addstr(7, 7, "( / |")
604+ bigdeer2.addstr(8, 8, "\\/ |")
605+ bigdeer2.addstr(9, 9, "|> |>")
606+
607+ bigdeer3.addch(0, 17, ord('\\'))
608+ bigdeer3.addch(0, 18, ord('/'))
609+ bigdeer3.addch(0, 19, ord('\\'))
610+ bigdeer3.addch(0, 20, ord('/'))
611+ bigdeer3.addch(1, 18, ord('\\'))
612+ bigdeer3.addch(1, 20, ord('/'))
613+ bigdeer3.addch(2, 19, ord('|'))
614+ bigdeer3.addch(2, 20, ord('_'))
615+ bigdeer3.addch(3, 18, ord('/'))
616+ bigdeer3.addch(3, 19, ord('^'))
617+ bigdeer3.addch(3, 20, ord('0'))
618+ bigdeer3.addch(3, 21, ord('\\'))
619+ bigdeer3.addch(4, 17, ord('/'))
620+ bigdeer3.addch(4, 18, ord('/'))
621+ bigdeer3.addch(4, 19, ord('\\'))
622+ bigdeer3.addch(4, 22, ord('\\'))
623+ bigdeer3.addstr(5, 7, "^~~~~~~~~// ~~U")
624+ bigdeer3.addstr(6, 6, "( ()_____( /") # ))
625+ bigdeer3.addstr(7, 6, "/ / /")
626+ bigdeer3.addstr(8, 5, "|/ \\")
627+ bigdeer3.addstr(9, 5, "/> \\>")
628+
629+ bigdeer4.addch(0, 17, ord('\\'))
630+ bigdeer4.addch(0, 18, ord('/'))
631+ bigdeer4.addch(0, 19, ord('\\'))
632+ bigdeer4.addch(0, 20, ord('/'))
633+ bigdeer4.addch(1, 18, ord('\\'))
634+ bigdeer4.addch(1, 20, ord('/'))
635+ bigdeer4.addch(2, 19, ord('|'))
636+ bigdeer4.addch(2, 20, ord('_'))
637+ bigdeer4.addch(3, 18, ord('/'))
638+ bigdeer4.addch(3, 19, ord('^'))
639+ bigdeer4.addch(3, 20, ord('0'))
640+ bigdeer4.addch(3, 21, ord('\\'))
641+ bigdeer4.addch(4, 17, ord('/'))
642+ bigdeer4.addch(4, 18, ord('/'))
643+ bigdeer4.addch(4, 19, ord('\\'))
644+ bigdeer4.addch(4, 22, ord('\\'))
645+ bigdeer4.addstr(5, 7, "^~~~~~~~~// ~~U")
646+ bigdeer4.addstr(6, 6, "( )______( /") # )
647+ bigdeer4.addstr(7, 5, "(/ \\") # )
648+ bigdeer4.addstr(8, 0, "v___= ----^")
649+
650+ lookdeer1.addstr(0, 16, "\\/ \\/")
651+ lookdeer1.addstr(1, 17, "\\Y/ \\Y/")
652+ lookdeer1.addstr(2, 19, "\\=/")
653+ lookdeer1.addstr(3, 17, "^\\o o/^")
654+ lookdeer1.addstr(4, 17, "//( )")
655+ lookdeer1.addstr(5, 7, "^~~~~~~~~// \\O/")
656+ lookdeer1.addstr(6, 7, "( \\_____( /") # ))
657+ lookdeer1.addstr(7, 8, "( ) /")
658+ lookdeer1.addstr(8, 9, "\\\\ /")
659+ lookdeer1.addstr(9, 11, "\\>/>")
660+
661+ lookdeer2.addstr(0, 16, "\\/ \\/")
662+ lookdeer2.addstr(1, 17, "\\Y/ \\Y/")
663+ lookdeer2.addstr(2, 19, "\\=/")
664+ lookdeer2.addstr(3, 17, "^\\o o/^")
665+ lookdeer2.addstr(4, 17, "//( )")
666+ lookdeer2.addstr(5, 7, "^~~~~~~~~// \\O/")
667+ lookdeer2.addstr(6, 7, "(( )____( /") # ))
668+ lookdeer2.addstr(7, 7, "( / |")
669+ lookdeer2.addstr(8, 8, "\\/ |")
670+ lookdeer2.addstr(9, 9, "|> |>")
671+
672+ lookdeer3.addstr(0, 16, "\\/ \\/")
673+ lookdeer3.addstr(1, 17, "\\Y/ \\Y/")
674+ lookdeer3.addstr(2, 19, "\\=/")
675+ lookdeer3.addstr(3, 17, "^\\o o/^")
676+ lookdeer3.addstr(4, 17, "//( )")
677+ lookdeer3.addstr(5, 7, "^~~~~~~~~// \\O/")
678+ lookdeer3.addstr(6, 6, "( ()_____( /") # ))
679+ lookdeer3.addstr(7, 6, "/ / /")
680+ lookdeer3.addstr(8, 5, "|/ \\")
681+ lookdeer3.addstr(9, 5, "/> \\>")
682+
683+ lookdeer4.addstr(0, 16, "\\/ \\/")
684+ lookdeer4.addstr(1, 17, "\\Y/ \\Y/")
685+ lookdeer4.addstr(2, 19, "\\=/")
686+ lookdeer4.addstr(3, 17, "^\\o o/^")
687+ lookdeer4.addstr(4, 17, "//( )")
688+ lookdeer4.addstr(5, 7, "^~~~~~~~~// \\O/")
689+ lookdeer4.addstr(6, 6, "( )______( /") # )
690+ lookdeer4.addstr(7, 5, "(/ \\") # )
691+ lookdeer4.addstr(8, 0, "v___= ----^")
692+
693+ ###############################################
694+ curses.cbreak()
695+ stdscr.nodelay(1)
696+
697+ while 1:
698+ stdscr.clear()
699+ treescrn.erase()
700+ w_del_msg.touchwin()
701+ treescrn.touchwin()
702+ treescrn2.erase()
703+ treescrn2.touchwin()
704+ treescrn8.erase()
705+ treescrn8.touchwin()
706+ stdscr.refresh()
707+ look_out(150)
708+ boxit()
709+ stdscr.refresh()
710+ look_out(150)
711+ seas()
712+ stdscr.refresh()
713+ greet()
714+ stdscr.refresh()
715+ look_out(150)
716+ fromwho()
717+ stdscr.refresh()
718+ look_out(150)
719+ tree()
720+ look_out(150)
721+ balls()
722+ look_out(150)
723+ star()
724+ look_out(150)
725+ strng1()
726+ strng2()
727+ strng3()
728+ strng4()
729+ strng5()
730+
731+ # set up the windows for our blinking trees
732+ #
733+ # treescrn3
734+ treescrn.overlay(treescrn3)
735+
736+ # balls
737+ treescrn3.addch(4, 18, ord(' '))
738+ treescrn3.addch(7, 6, ord(' '))
739+ treescrn3.addch(8, 19, ord(' '))
740+ treescrn3.addch(11, 22, ord(' '))
741+
742+ # star
743+ treescrn3.addch(0, 12, ord('*'))
744+
745+ # strng1
746+ treescrn3.addch(3, 11, ord(' '))
747+
748+ # strng2
749+ treescrn3.addch(5, 13, ord(' '))
750+ treescrn3.addch(6, 10, ord(' '))
751+
752+ # strng3
753+ treescrn3.addch(7, 16, ord(' '))
754+ treescrn3.addch(7, 14, ord(' '))
755+
756+ # strng4
757+ treescrn3.addch(10, 13, ord(' '))
758+ treescrn3.addch(10, 10, ord(' '))
759+ treescrn3.addch(11, 8, ord(' '))
760+
761+ # strng5
762+ treescrn3.addch(11, 18, ord(' '))
763+ treescrn3.addch(12, 13, ord(' '))
764+
765+ # treescrn4
766+ treescrn.overlay(treescrn4)
767+
768+ # balls
769+ treescrn4.addch(3, 9, ord(' '))
770+ treescrn4.addch(4, 16, ord(' '))
771+ treescrn4.addch(7, 6, ord(' '))
772+ treescrn4.addch(8, 19, ord(' '))
773+ treescrn4.addch(11, 2, ord(' '))
774+ treescrn4.addch(12, 23, ord(' '))
775+
776+ # star
777+ treescrn4.standout()
778+ treescrn4.addch(0, 12, ord('*'))
779+ treescrn4.standend()
780+
781+ # strng1
782+ treescrn4.addch(3, 13, ord(' '))
783+
784+ # strng2
785+
786+ # strng3
787+ treescrn4.addch(7, 15, ord(' '))
788+ treescrn4.addch(8, 11, ord(' '))
789+
790+ # strng4
791+ treescrn4.addch(9, 16, ord(' '))
792+ treescrn4.addch(10, 12, ord(' '))
793+ treescrn4.addch(11, 8, ord(' '))
794+
795+ # strng5
796+ treescrn4.addch(11, 18, ord(' '))
797+ treescrn4.addch(12, 14, ord(' '))
798+
799+ # treescrn5
800+ treescrn.overlay(treescrn5)
801+
802+ # balls
803+ treescrn5.addch(3, 15, ord(' '))
804+ treescrn5.addch(10, 20, ord(' '))
805+ treescrn5.addch(12, 1, ord(' '))
806+
807+ # star
808+ treescrn5.addch(0, 12, ord(' '))
809+
810+ # strng1
811+ treescrn5.addch(3, 11, ord(' '))
812+
813+ # strng2
814+ treescrn5.addch(5, 12, ord(' '))
815+
816+ # strng3
817+ treescrn5.addch(7, 14, ord(' '))
818+ treescrn5.addch(8, 10, ord(' '))
819+
820+ # strng4
821+ treescrn5.addch(9, 15, ord(' '))
822+ treescrn5.addch(10, 11, ord(' '))
823+ treescrn5.addch(11, 7, ord(' '))
824+
825+ # strng5
826+ treescrn5.addch(11, 17, ord(' '))
827+ treescrn5.addch(12, 13, ord(' '))
828+
829+ # treescrn6
830+ treescrn.overlay(treescrn6)
831+
832+ # balls
833+ treescrn6.addch(6, 7, ord(' '))
834+ treescrn6.addch(7, 18, ord(' '))
835+ treescrn6.addch(10, 4, ord(' '))
836+ treescrn6.addch(11, 23, ord(' '))
837+
838+ # star
839+ treescrn6.standout()
840+ treescrn6.addch(0, 12, ord('*'))
841+ treescrn6.standend()
842+
843+ # strng1
844+
845+ # strng2
846+ treescrn6.addch(5, 11, ord(' '))
847+
848+ # strng3
849+ treescrn6.addch(7, 13, ord(' '))
850+ treescrn6.addch(8, 9, ord(' '))
851+
852+ # strng4
853+ treescrn6.addch(9, 14, ord(' '))
854+ treescrn6.addch(10, 10, ord(' '))
855+ treescrn6.addch(11, 6, ord(' '))
856+
857+ # strng5
858+ treescrn6.addch(11, 16, ord(' '))
859+ treescrn6.addch(12, 12, ord(' '))
860+
861+ # treescrn7
862+
863+ treescrn.overlay(treescrn7)
864+
865+ # balls
866+ treescrn7.addch(3, 15, ord(' '))
867+ treescrn7.addch(6, 7, ord(' '))
868+ treescrn7.addch(7, 18, ord(' '))
869+ treescrn7.addch(10, 4, ord(' '))
870+ treescrn7.addch(11, 22, ord(' '))
871+
872+ # star
873+ treescrn7.addch(0, 12, ord('*'))
874+
875+ # strng1
876+ treescrn7.addch(3, 12, ord(' '))
877+
878+ # strng2
879+ treescrn7.addch(5, 13, ord(' '))
880+ treescrn7.addch(6, 9, ord(' '))
881+
882+ # strng3
883+ treescrn7.addch(7, 15, ord(' '))
884+ treescrn7.addch(8, 11, ord(' '))
885+
886+ # strng4
887+ treescrn7.addch(9, 16, ord(' '))
888+ treescrn7.addch(10, 12, ord(' '))
889+ treescrn7.addch(11, 8, ord(' '))
890+
891+ # strng5
892+ treescrn7.addch(11, 18, ord(' '))
893+ treescrn7.addch(12, 14, ord(' '))
894+
895+ look_out(150)
896+ reindeer()
897+
898+ w_holiday.touchwin()
899+ w_holiday.refresh()
900+ w_del_msg.refresh()
901+
902+ look_out(500)
903+ for i in range(0, 20):
904+ blinkit()
905+
906+curses.wrapper(main)
sys/src/cmd/python/Demo/embed/Makefile+57−0
@@ -0,0 +1,57 @@
1+# Makefile for embedded Python use demo.
2+# (This version tailored for my Red Hat Linux 6.1 setup;
3+# edit lines marked with XXX.)
4+
5+# XXX The compiler you are using
6+CC= gcc
7+
8+# XXX Top of the build tree and source tree
9+blddir= ../..
10+srcdir= ../..
11+
12+# Python version
13+VERSION= 2.5
14+
15+# Compiler flags
16+OPT= -g
17+INCLUDES= -I$(srcdir)/Include -I$(blddir)
18+CFLAGS= $(OPT)
19+CPPFLAGS= $(INCLUDES)
20+
21+# The Python library
22+LIBPYTHON= $(blddir)/libpython$(VERSION).a
23+
24+# XXX edit LIBS (in particular) to match $(blddir)/Modules/Makefile
25+LIBS= -lnsl -ldl -lreadline -ltermcap -lieee -lpthread -lutil
26+LDFLAGS= -Xlinker -export-dynamic
27+SYSLIBS= -lm
28+MODLIBS=
29+ALLLIBS= $(LIBPYTHON) $(MODLIBS) $(LIBS) $(SYSLIBS)
30+
31+# Build the demo applications
32+all: demo loop importexc
33+demo: demo.o
34+ $(CC) $(LDFLAGS) demo.o $(ALLLIBS) -o demo
35+
36+loop: loop.o
37+ $(CC) $(LDFLAGS) loop.o $(ALLLIBS) -o loop
38+
39+importexc: importexc.o
40+ $(CC) $(LDFLAGS) importexc.o $(ALLLIBS) -o importexc
41+
42+# Administrative targets
43+
44+test: demo
45+ ./demo
46+
47+COMMAND="print 'hello world'"
48+looptest: loop
49+ ./loop $(COMMAND)
50+
51+clean:
52+ -rm -f *.o core
53+
54+clobber: clean
55+ -rm -f *~ @* '#'* demo loop importexc
56+
57+realclean: clobber
sys/src/cmd/python/Demo/embed/README+19−0
@@ -0,0 +1,19 @@
1+This directory show how to embed the Python interpreter in your own
2+application. The file demo.c shows you all that is needed in your C
3+code.
4+
5+To build it, you may have to edit the Makefile:
6+
7+1) set blddir to the directory where you built Python, if it isn't in
8+the source directory (../..)
9+
10+2) change the variables that together define the list of libraries
11+(MODLIBS, LIBS, SYSLIBS) to link with, to match their definitions in
12+$(blddir)/Modules/Makefile
13+
14+An additional test program, loop.c, is used to experiment with memory
15+leakage caused by repeated initialization and finalization of the
16+interpreter. It can be build by saying "make loop" and tested with
17+"make looptest". Command line usage is "./loop <python-command>",
18+e.g. "./loop 'print 2+2'" should spit out an endless number of lines
19+containing the number 4.
sys/src/cmd/python/Demo/embed/demo.c+65−0
@@ -0,0 +1,65 @@
1+/* Example of embedding Python in another program */
2+
3+#include "Python.h"
4+
5+void initxyzzy(void); /* Forward */
6+
7+main(int argc, char **argv)
8+{
9+ /* Pass argv[0] to the Python interpreter */
10+ Py_SetProgramName(argv[0]);
11+
12+ /* Initialize the Python interpreter. Required. */
13+ Py_Initialize();
14+
15+ /* Add a static module */
16+ initxyzzy();
17+
18+ /* Define sys.argv. It is up to the application if you
19+ want this; you can also let it undefined (since the Python
20+ code is generally not a main program it has no business
21+ touching sys.argv...) */
22+ PySys_SetArgv(argc, argv);
23+
24+ /* Do some application specific code */
25+ printf("Hello, brave new world\n\n");
26+
27+ /* Execute some Python statements (in module __main__) */
28+ PyRun_SimpleString("import sys\n");
29+ PyRun_SimpleString("print sys.builtin_module_names\n");
30+ PyRun_SimpleString("print sys.modules.keys()\n");
31+ PyRun_SimpleString("print sys.executable\n");
32+ PyRun_SimpleString("print sys.argv\n");
33+
34+ /* Note that you can call any public function of the Python
35+ interpreter here, e.g. call_object(). */
36+
37+ /* Some more application specific code */
38+ printf("\nGoodbye, cruel world\n");
39+
40+ /* Exit, cleaning up the interpreter */
41+ Py_Exit(0);
42+ /*NOTREACHED*/
43+}
44+
45+/* A static module */
46+
47+/* 'self' is not used */
48+static PyObject *
49+xyzzy_foo(PyObject *self, PyObject* args)
50+{
51+ return PyInt_FromLong(42L);
52+}
53+
54+static PyMethodDef xyzzy_methods[] = {
55+ {"foo", xyzzy_foo, METH_NOARGS,
56+ "Return the meaning of everything."},
57+ {NULL, NULL} /* sentinel */
58+};
59+
60+void
61+initxyzzy(void)
62+{
63+ PyImport_AddModule("xyzzy");
64+ Py_InitModule("xyzzy", xyzzy_methods);
65+}
sys/src/cmd/python/Demo/embed/importexc.c+17−0
@@ -0,0 +1,17 @@
1+#include <Python.h>
2+
3+char* cmd = "import exceptions";
4+
5+int main()
6+{
7+ Py_Initialize();
8+ PyEval_InitThreads();
9+ PyRun_SimpleString(cmd);
10+ Py_EndInterpreter(PyThreadState_Get());
11+
12+ Py_NewInterpreter();
13+ PyRun_SimpleString(cmd);
14+ Py_Finalize();
15+
16+ return 0;
17+}
sys/src/cmd/python/Demo/embed/loop.c+33−0
@@ -0,0 +1,33 @@
1+/* Simple program that repeatedly calls Py_Initialize(), does something, and
2+ then calls Py_Finalize(). This should help finding leaks related to
3+ initialization. */
4+
5+#include "Python.h"
6+
7+main(int argc, char **argv)
8+{
9+ int count = -1;
10+ char *command;
11+
12+ if (argc < 2 || argc > 3) {
13+ fprintf(stderr, "usage: loop <python-command> [count]\n");
14+ exit(2);
15+ }
16+ command = argv[1];
17+
18+ if (argc == 3) {
19+ count = atoi(argv[2]);
20+ }
21+
22+ Py_SetProgramName(argv[0]);
23+
24+ /* uncomment this if you don't want to load site.py */
25+ /* Py_NoSiteFlag = 1; */
26+
27+ while (count == -1 || --count >= 0 ) {
28+ Py_Initialize();
29+ PyRun_SimpleString(command);
30+ Py_Finalize();
31+ }
32+ return 0;
33+}
sys/src/cmd/python/Demo/imputil/importers.py+248−0
@@ -0,0 +1,248 @@
1+#
2+# importers.py
3+#
4+# Demonstration subclasses of imputil.Importer
5+#
6+
7+# There should be consideration for the imports below if it is desirable
8+# to have "all" modules be imported through the imputil system.
9+
10+# these are C extensions
11+import sys
12+import imp
13+import struct
14+import marshal
15+
16+# these are .py modules
17+import imputil
18+import os
19+
20+######################################################################
21+
22+_TupleType = type(())
23+_StringType = type('')
24+
25+######################################################################
26+
27+# byte-compiled file suffic character
28+_suffix_char = __debug__ and 'c' or 'o'
29+
30+# byte-compiled file suffix
31+_suffix = '.py' + _suffix_char
32+
33+# the C_EXTENSION suffixes
34+_c_suffixes = filter(lambda x: x[2] == imp.C_EXTENSION, imp.get_suffixes())
35+
36+def _timestamp(pathname):
37+ "Return the file modification time as a Long."
38+ try:
39+ s = os.stat(pathname)
40+ except OSError:
41+ return None
42+ return long(s[8])
43+
44+def _fs_import(dir, modname, fqname):
45+ "Fetch a module from the filesystem."
46+
47+ pathname = os.path.join(dir, modname)
48+ if os.path.isdir(pathname):
49+ values = { '__pkgdir__' : pathname, '__path__' : [ pathname ] }
50+ ispkg = 1
51+ pathname = os.path.join(pathname, '__init__')
52+ else:
53+ values = { }
54+ ispkg = 0
55+
56+ # look for dynload modules
57+ for desc in _c_suffixes:
58+ file = pathname + desc[0]
59+ try:
60+ fp = open(file, desc[1])
61+ except IOError:
62+ pass
63+ else:
64+ module = imp.load_module(fqname, fp, file, desc)
65+ values['__file__'] = file
66+ return 0, module, values
67+
68+ t_py = _timestamp(pathname + '.py')
69+ t_pyc = _timestamp(pathname + _suffix)
70+ if t_py is None and t_pyc is None:
71+ return None
72+ code = None
73+ if t_py is None or (t_pyc is not None and t_pyc >= t_py):
74+ file = pathname + _suffix
75+ f = open(file, 'rb')
76+ if f.read(4) == imp.get_magic():
77+ t = struct.unpack('<I', f.read(4))[0]
78+ if t == t_py:
79+ code = marshal.load(f)
80+ f.close()
81+ if code is None:
82+ file = pathname + '.py'
83+ code = _compile(file, t_py)
84+
85+ values['__file__'] = file
86+ return ispkg, code, values
87+
88+######################################################################
89+#
90+# Simple function-based importer
91+#
92+class FuncImporter(imputil.Importer):
93+ "Importer subclass to delegate to a function rather than method overrides."
94+ def __init__(self, func):
95+ self.func = func
96+ def get_code(self, parent, modname, fqname):
97+ return self.func(parent, modname, fqname)
98+
99+def install_with(func):
100+ FuncImporter(func).install()
101+
102+
103+######################################################################
104+#
105+# Base class for archive-based importing
106+#
107+class PackageArchiveImporter(imputil.Importer):
108+ """Importer subclass to import from (file) archives.
109+
110+ This Importer handles imports of the style <archive>.<subfile>, where
111+ <archive> can be located using a subclass-specific mechanism and the
112+ <subfile> is found in the archive using a subclass-specific mechanism.
113+
114+ This class defines two hooks for subclasses: one to locate an archive
115+ (and possibly return some context for future subfile lookups), and one
116+ to locate subfiles.
117+ """
118+
119+ def get_code(self, parent, modname, fqname):
120+ if parent:
121+ # the Importer._finish_import logic ensures that we handle imports
122+ # under the top level module (package / archive).
123+ assert parent.__importer__ == self
124+
125+ # if a parent "package" is provided, then we are importing a
126+ # sub-file from the archive.
127+ result = self.get_subfile(parent.__archive__, modname)
128+ if result is None:
129+ return None
130+ if isinstance(result, _TupleType):
131+ assert len(result) == 2
132+ return (0,) + result
133+ return 0, result, {}
134+
135+ # no parent was provided, so the archive should exist somewhere on the
136+ # default "path".
137+ archive = self.get_archive(modname)
138+ if archive is None:
139+ return None
140+ return 1, "", {'__archive__':archive}
141+
142+ def get_archive(self, modname):
143+ """Get an archive of modules.
144+
145+ This method should locate an archive and return a value which can be
146+ used by get_subfile to load modules from it. The value may be a simple
147+ pathname, an open file, or a complex object that caches information
148+ for future imports.
149+
150+ Return None if the archive was not found.
151+ """
152+ raise RuntimeError, "get_archive not implemented"
153+
154+ def get_subfile(self, archive, modname):
155+ """Get code from a subfile in the specified archive.
156+
157+ Given the specified archive (as returned by get_archive()), locate
158+ and return a code object for the specified module name.
159+
160+ A 2-tuple may be returned, consisting of a code object and a dict
161+ of name/values to place into the target module.
162+
163+ Return None if the subfile was not found.
164+ """
165+ raise RuntimeError, "get_subfile not implemented"
166+
167+
168+class PackageArchive(PackageArchiveImporter):
169+ "PackageArchiveImporter subclass that refers to a specific archive."
170+
171+ def __init__(self, modname, archive_pathname):
172+ self.__modname = modname
173+ self.__path = archive_pathname
174+
175+ def get_archive(self, modname):
176+ if modname == self.__modname:
177+ return self.__path
178+ return None
179+
180+ # get_subfile is passed the full pathname of the archive
181+
182+
183+######################################################################
184+#
185+# Emulate the standard directory-based import mechanism
186+#
187+class DirectoryImporter(imputil.Importer):
188+ "Importer subclass to emulate the standard importer."
189+
190+ def __init__(self, dir):
191+ self.dir = dir
192+
193+ def get_code(self, parent, modname, fqname):
194+ if parent:
195+ dir = parent.__pkgdir__
196+ else:
197+ dir = self.dir
198+
199+ # Return the module (and other info) if found in the specified
200+ # directory. Otherwise, return None.
201+ return _fs_import(dir, modname, fqname)
202+
203+ def __repr__(self):
204+ return '<%s.%s for "%s" at 0x%x>' % (self.__class__.__module__,
205+ self.__class__.__name__,
206+ self.dir,
207+ id(self))
208+
209+
210+######################################################################
211+#
212+# Emulate the standard path-style import mechanism
213+#
214+class PathImporter(imputil.Importer):
215+ def __init__(self, path=sys.path):
216+ self.path = path
217+
218+ def get_code(self, parent, modname, fqname):
219+ if parent:
220+ # we are looking for a module inside of a specific package
221+ return _fs_import(parent.__pkgdir__, modname, fqname)
222+
223+ # scan sys.path, looking for the requested module
224+ for dir in self.path:
225+ if isinstance(dir, _StringType):
226+ result = _fs_import(dir, modname, fqname)
227+ if result:
228+ return result
229+
230+ # not found
231+ return None
232+
233+######################################################################
234+
235+def _test_dir():
236+ "Debug/test function to create DirectoryImporters from sys.path."
237+ imputil.ImportManager().install()
238+ path = sys.path[:]
239+ path.reverse()
240+ for d in path:
241+ sys.path.insert(0, DirectoryImporter(d))
242+ sys.path.insert(0, imputil.BuiltinImporter())
243+
244+def _test_revamp():
245+ "Debug/test function for the revamped import system."
246+ imputil.ImportManager().install()
247+ sys.path.insert(0, PathImporter())
248+ sys.path.insert(0, imputil.BuiltinImporter())
sys/src/cmd/python/Demo/imputil/knee.py+126−0
@@ -0,0 +1,126 @@
1+"""An Python re-implementation of hierarchical module import.
2+
3+This code is intended to be read, not executed. However, it does work
4+-- all you need to do to enable it is "import knee".
5+
6+(The name is a pun on the klunkier predecessor of this module, "ni".)
7+
8+"""
9+
10+import sys, imp, __builtin__
11+
12+
13+# Replacement for __import__()
14+def import_hook(name, globals=None, locals=None, fromlist=None):
15+ parent = determine_parent(globals)
16+ q, tail = find_head_package(parent, name)
17+ m = load_tail(q, tail)
18+ if not fromlist:
19+ return q
20+ if hasattr(m, "__path__"):
21+ ensure_fromlist(m, fromlist)
22+ return m
23+
24+def determine_parent(globals):
25+ if not globals or not globals.has_key("__name__"):
26+ return None
27+ pname = globals['__name__']
28+ if globals.has_key("__path__"):
29+ parent = sys.modules[pname]
30+ assert globals is parent.__dict__
31+ return parent
32+ if '.' in pname:
33+ i = pname.rfind('.')
34+ pname = pname[:i]
35+ parent = sys.modules[pname]
36+ assert parent.__name__ == pname
37+ return parent
38+ return None
39+
40+def find_head_package(parent, name):
41+ if '.' in name:
42+ i = name.find('.')
43+ head = name[:i]
44+ tail = name[i+1:]
45+ else:
46+ head = name
47+ tail = ""
48+ if parent:
49+ qname = "%s.%s" % (parent.__name__, head)
50+ else:
51+ qname = head
52+ q = import_module(head, qname, parent)
53+ if q: return q, tail
54+ if parent:
55+ qname = head
56+ parent = None
57+ q = import_module(head, qname, parent)
58+ if q: return q, tail
59+ raise ImportError, "No module named " + qname
60+
61+def load_tail(q, tail):
62+ m = q
63+ while tail:
64+ i = tail.find('.')
65+ if i < 0: i = len(tail)
66+ head, tail = tail[:i], tail[i+1:]
67+ mname = "%s.%s" % (m.__name__, head)
68+ m = import_module(head, mname, m)
69+ if not m:
70+ raise ImportError, "No module named " + mname
71+ return m
72+
73+def ensure_fromlist(m, fromlist, recursive=0):
74+ for sub in fromlist:
75+ if sub == "*":
76+ if not recursive:
77+ try:
78+ all = m.__all__
79+ except AttributeError:
80+ pass
81+ else:
82+ ensure_fromlist(m, all, 1)
83+ continue
84+ if sub != "*" and not hasattr(m, sub):
85+ subname = "%s.%s" % (m.__name__, sub)
86+ submod = import_module(sub, subname, m)
87+ if not submod:
88+ raise ImportError, "No module named " + subname
89+
90+def import_module(partname, fqname, parent):
91+ try:
92+ return sys.modules[fqname]
93+ except KeyError:
94+ pass
95+ try:
96+ fp, pathname, stuff = imp.find_module(partname,
97+ parent and parent.__path__)
98+ except ImportError:
99+ return None
100+ try:
101+ m = imp.load_module(fqname, fp, pathname, stuff)
102+ finally:
103+ if fp: fp.close()
104+ if parent:
105+ setattr(parent, partname, m)
106+ return m
107+
108+
109+# Replacement for reload()
110+def reload_hook(module):
111+ name = module.__name__
112+ if '.' not in name:
113+ return import_module(name, name, None)
114+ i = name.rfind('.')
115+ pname = name[:i]
116+ parent = sys.modules[pname]
117+ return import_module(name[i+1:], name, parent)
118+
119+
120+# Save the original hooks
121+original_import = __builtin__.__import__
122+original_reload = __builtin__.reload
123+
124+# Now install our hooks
125+__builtin__.__import__ = import_hook
126+__builtin__.reload = reload_hook
sys/src/cmd/python/Demo/md5test/README+10−0
@@ -0,0 +1,10 @@
1+This is the Python version of the MD5 test program from the MD5
2+Internet Draft (Rivest and Dusse, The MD5 Message-Digest Algorithm, 10
3+July 1991). The file "foo" contains the string "abc" with no trailing
4+newline.
5+
6+When called without arguments, it acts as a filter. When called with
7+"-x", it executes a self-test, and the output should literally match
8+the output given in the RFC.
9+
10+Code by Jan-Hein B\"uhrman after the original in C.
sys/src/cmd/python/Demo/md5test/foo+1−0
@@ -0,0 +1 @@
1+abc
sys/src/cmd/python/Demo/md5test/md5driver.py+123−0
@@ -0,0 +1,123 @@
1+import string
2+import md5
3+from sys import argv
4+
5+def MDPrint(str):
6+ outstr = ''
7+ for i in str:
8+ o = ord(i)
9+ outstr = (outstr
10+ + string.hexdigits[(o >> 4) & 0xF]
11+ + string.hexdigits[o & 0xF])
12+ print outstr,
13+
14+
15+from time import time
16+
17+def makestr(start, end):
18+ result = ''
19+ for i in range(start, end + 1):
20+ result = result + chr(i)
21+
22+ return result
23+
24+
25+def MDTimeTrial():
26+ TEST_BLOCK_SIZE = 1000
27+ TEST_BLOCKS = 10000
28+
29+ TEST_BYTES = TEST_BLOCK_SIZE * TEST_BLOCKS
30+
31+ # initialize test data, need temporary string filler
32+
33+ filsiz = 1 << 8
34+ filler = makestr(0, filsiz-1)
35+ data = filler * (TEST_BLOCK_SIZE / filsiz);
36+ data = data + filler[:(TEST_BLOCK_SIZE % filsiz)]
37+
38+ del filsiz, filler
39+
40+
41+ # start timer
42+ print 'MD5 time trial. Processing', TEST_BYTES, 'characters...'
43+ t1 = time()
44+
45+ mdContext = md5.new()
46+
47+ for i in range(TEST_BLOCKS):
48+ mdContext.update(data)
49+
50+ str = mdContext.digest()
51+ t2 = time()
52+
53+ MDPrint(str)
54+ print 'is digest of test input.'
55+ print 'Seconds to process test input:', t2 - t1
56+ print 'Characters processed per second:', TEST_BYTES / (t2 - t1)
57+
58+
59+def MDString(str):
60+ MDPrint(md5.new(str).digest())
61+ print '"' + str + '"'
62+
63+
64+def MDFile(filename):
65+ f = open(filename, 'rb');
66+ mdContext = md5.new()
67+
68+ while 1:
69+ data = f.read(1024)
70+ if not data:
71+ break
72+ mdContext.update(data)
73+
74+ MDPrint(mdContext.digest())
75+ print filename
76+
77+
78+import sys
79+
80+def MDFilter():
81+ mdContext = md5.new()
82+
83+ while 1:
84+ data = sys.stdin.read(16)
85+ if not data:
86+ break
87+ mdContext.update(data)
88+
89+ MDPrint(mdContext.digest())
90+ print
91+
92+
93+def MDTestSuite():
94+ print 'MD5 test suite results:'
95+ MDString('')
96+ MDString('a')
97+ MDString('abc')
98+ MDString('message digest')
99+ MDString(makestr(ord('a'), ord('z')))
100+ MDString(makestr(ord('A'), ord('Z'))
101+ + makestr(ord('a'), ord('z'))
102+ + makestr(ord('0'), ord('9')))
103+ MDString((makestr(ord('1'), ord('9')) + '0') * 8)
104+
105+ # Contents of file foo are "abc"
106+ MDFile('foo')
107+
108+
109+# I don't wanna use getopt(), since I want to use the same i/f...
110+def main():
111+ if len(argv) == 1:
112+ MDFilter()
113+ for arg in argv[1:]:
114+ if arg[:2] == '-s':
115+ MDString(arg[2:])
116+ elif arg == '-t':
117+ MDTimeTrial()
118+ elif arg == '-x':
119+ MDTestSuite()
120+ else:
121+ MDFile(arg)
122+
123+main()
sys/src/cmd/python/Demo/metaclasses/Eiffel.py+113−0
@@ -0,0 +1,113 @@
1+"""Support Eiffel-style preconditions and postconditions.
2+
3+For example,
4+
5+class C:
6+ def m1(self, arg):
7+ require arg > 0
8+ return whatever
9+ ensure Result > arg
10+
11+can be written (clumsily, I agree) as:
12+
13+class C(Eiffel):
14+ def m1(self, arg):
15+ return whatever
16+ def m1_pre(self, arg):
17+ assert arg > 0
18+ def m1_post(self, Result, arg):
19+ assert Result > arg
20+
21+Pre- and post-conditions for a method, being implemented as methods
22+themselves, are inherited independently from the method. This gives
23+much of the same effect of Eiffel, where pre- and post-conditions are
24+inherited when a method is overridden by a derived class. However,
25+when a derived class in Python needs to extend a pre- or
26+post-condition, it must manually merge the base class' pre- or
27+post-condition with that defined in the derived class', for example:
28+
29+class D(C):
30+ def m1(self, arg):
31+ return arg**2
32+ def m1_post(self, Result, arg):
33+ C.m1_post(self, Result, arg)
34+ assert Result < 100
35+
36+This gives derived classes more freedom but also more responsibility
37+than in Eiffel, where the compiler automatically takes care of this.
38+
39+In Eiffel, pre-conditions combine using contravariance, meaning a
40+derived class can only make a pre-condition weaker; in Python, this is
41+up to the derived class. For example, a derived class that takes away
42+the requirement that arg > 0 could write:
43+
44+ def m1_pre(self, arg):
45+ pass
46+
47+but one could equally write a derived class that makes a stronger
48+requirement:
49+
50+ def m1_pre(self, arg):
51+ require arg > 50
52+
53+It would be easy to modify the classes shown here so that pre- and
54+post-conditions can be disabled (separately, on a per-class basis).
55+
56+A different design would have the pre- or post-condition testing
57+functions return true for success and false for failure. This would
58+make it possible to implement automatic combination of inherited
59+and new pre-/post-conditions. All this is left as an exercise to the
60+reader.
61+
62+"""
63+
64+from Meta import MetaClass, MetaHelper, MetaMethodWrapper
65+
66+class EiffelMethodWrapper(MetaMethodWrapper):
67+
68+ def __init__(self, func, inst):
69+ MetaMethodWrapper.__init__(self, func, inst)
70+ # Note that the following causes recursive wrappers around
71+ # the pre-/post-condition testing methods. These are harmless
72+ # but inefficient; to avoid them, the lookup must be done
73+ # using the class.
74+ try:
75+ self.pre = getattr(inst, self.__name__ + "_pre")
76+ except AttributeError:
77+ self.pre = None
78+ try:
79+ self.post = getattr(inst, self.__name__ + "_post")
80+ except AttributeError:
81+ self.post = None
82+
83+ def __call__(self, *args, **kw):
84+ if self.pre:
85+ apply(self.pre, args, kw)
86+ Result = apply(self.func, (self.inst,) + args, kw)
87+ if self.post:
88+ apply(self.post, (Result,) + args, kw)
89+ return Result
90+
91+class EiffelHelper(MetaHelper):
92+ __methodwrapper__ = EiffelMethodWrapper
93+
94+class EiffelMetaClass(MetaClass):
95+ __helper__ = EiffelHelper
96+
97+Eiffel = EiffelMetaClass('Eiffel', (), {})
98+
99+
100+def _test():
101+ class C(Eiffel):
102+ def m1(self, arg):
103+ return arg+1
104+ def m1_pre(self, arg):
105+ assert arg > 0, "precondition for m1 failed"
106+ def m1_post(self, Result, arg):
107+ assert Result > arg
108+ x = C()
109+ x.m1(12)
110+## x.m1(-1)
111+
112+if __name__ == '__main__':
113+ _test()
sys/src/cmd/python/Demo/metaclasses/Enum.py+169−0
@@ -0,0 +1,169 @@
1+"""Enumeration metaclass.
2+
3+XXX This is very much a work in progress.
4+
5+"""
6+
7+import string
8+
9+class EnumMetaClass:
10+ """Metaclass for enumeration.
11+
12+ To define your own enumeration, do something like
13+
14+ class Color(Enum):
15+ red = 1
16+ green = 2
17+ blue = 3
18+
19+ Now, Color.red, Color.green and Color.blue behave totally
20+ different: they are enumerated values, not integers.
21+
22+ Enumerations cannot be instantiated; however they can be
23+ subclassed.
24+
25+ """
26+
27+ def __init__(self, name, bases, dict):
28+ """Constructor -- create an enumeration.
29+
30+ Called at the end of the class statement. The arguments are
31+ the name of the new class, a tuple containing the base
32+ classes, and a dictionary containing everything that was
33+ entered in the class' namespace during execution of the class
34+ statement. In the above example, it would be {'red': 1,
35+ 'green': 2, 'blue': 3}.
36+
37+ """
38+ for base in bases:
39+ if base.__class__ is not EnumMetaClass:
40+ raise TypeError, "Enumeration base class must be enumeration"
41+ bases = filter(lambda x: x is not Enum, bases)
42+ self.__name__ = name
43+ self.__bases__ = bases
44+ self.__dict = {}
45+ for key, value in dict.items():
46+ self.__dict[key] = EnumInstance(name, key, value)
47+
48+ def __getattr__(self, name):
49+ """Return an enumeration value.
50+
51+ For example, Color.red returns the value corresponding to red.
52+
53+ XXX Perhaps the values should be created in the constructor?
54+
55+ This looks in the class dictionary and if it is not found
56+ there asks the base classes.
57+
58+ The special attribute __members__ returns the list of names
59+ defined in this class (it does not merge in the names defined
60+ in base classes).
61+
62+ """
63+ if name == '__members__':
64+ return self.__dict.keys()
65+
66+ try:
67+ return self.__dict[name]
68+ except KeyError:
69+ for base in self.__bases__:
70+ try:
71+ return getattr(base, name)
72+ except AttributeError:
73+ continue
74+
75+ raise AttributeError, name
76+
77+ def __repr__(self):
78+ s = self.__name__
79+ if self.__bases__:
80+ s = s + '(' + string.join(map(lambda x: x.__name__,
81+ self.__bases__), ", ") + ')'
82+ if self.__dict:
83+ list = []
84+ for key, value in self.__dict.items():
85+ list.append("%s: %s" % (key, int(value)))
86+ s = "%s: {%s}" % (s, string.join(list, ", "))
87+ return s
88+
89+
90+class EnumInstance:
91+ """Class to represent an enumeration value.
92+
93+ EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
94+ like the integer 12 when compared, but doesn't support arithmetic.
95+
96+ XXX Should it record the actual enumeration rather than just its
97+ name?
98+
99+ """
100+
101+ def __init__(self, classname, enumname, value):
102+ self.__classname = classname
103+ self.__enumname = enumname
104+ self.__value = value
105+
106+ def __int__(self):
107+ return self.__value
108+
109+ def __repr__(self):
110+ return "EnumInstance(%r, %r, %r)" % (self.__classname,
111+ self.__enumname,
112+ self.__value)
113+
114+ def __str__(self):
115+ return "%s.%s" % (self.__classname, self.__enumname)
116+
117+ def __cmp__(self, other):
118+ return cmp(self.__value, int(other))
119+
120+
121+# Create the base class for enumerations.
122+# It is an empty enumeration.
123+Enum = EnumMetaClass("Enum", (), {})
124+
125+
126+def _test():
127+
128+ class Color(Enum):
129+ red = 1
130+ green = 2
131+ blue = 3
132+
133+ print Color.red
134+ print dir(Color)
135+
136+ print Color.red == Color.red
137+ print Color.red == Color.blue
138+ print Color.red == 1
139+ print Color.red == 2
140+
141+ class ExtendedColor(Color):
142+ white = 0
143+ orange = 4
144+ yellow = 5
145+ purple = 6
146+ black = 7
147+
148+ print ExtendedColor.orange
149+ print ExtendedColor.red
150+
151+ print Color.red == ExtendedColor.red
152+
153+ class OtherColor(Enum):
154+ white = 4
155+ blue = 5
156+
157+ class MergedColor(Color, OtherColor):
158+ pass
159+
160+ print MergedColor.red
161+ print MergedColor.white
162+
163+ print Color
164+ print ExtendedColor
165+ print OtherColor
166+ print MergedColor
167+
168+if __name__ == '__main__':
169+ _test()
sys/src/cmd/python/Demo/metaclasses/Meta.py+118−0
@@ -0,0 +1,118 @@
1+"""Generic metaclass.
2+
3+XXX This is very much a work in progress.
4+
5+"""
6+
7+import types
8+
9+class MetaMethodWrapper:
10+
11+ def __init__(self, func, inst):
12+ self.func = func
13+ self.inst = inst
14+ self.__name__ = self.func.__name__
15+
16+ def __call__(self, *args, **kw):
17+ return apply(self.func, (self.inst,) + args, kw)
18+
19+class MetaHelper:
20+
21+ __methodwrapper__ = MetaMethodWrapper # For derived helpers to override
22+
23+ def __helperinit__(self, formalclass):
24+ self.__formalclass__ = formalclass
25+
26+ def __getattr__(self, name):
27+ # Invoked for any attr not in the instance's __dict__
28+ try:
29+ raw = self.__formalclass__.__getattr__(name)
30+ except AttributeError:
31+ try:
32+ ga = self.__formalclass__.__getattr__('__usergetattr__')
33+ except (KeyError, AttributeError):
34+ raise AttributeError, name
35+ return ga(self, name)
36+ if type(raw) != types.FunctionType:
37+ return raw
38+ return self.__methodwrapper__(raw, self)
39+
40+class MetaClass:
41+
42+ """A generic metaclass.
43+
44+ This can be subclassed to implement various kinds of meta-behavior.
45+
46+ """
47+
48+ __helper__ = MetaHelper # For derived metaclasses to override
49+
50+ __inited = 0
51+
52+ def __init__(self, name, bases, dict):
53+ try:
54+ ga = dict['__getattr__']
55+ except KeyError:
56+ pass
57+ else:
58+ dict['__usergetattr__'] = ga
59+ del dict['__getattr__']
60+ self.__name__ = name
61+ self.__bases__ = bases
62+ self.__realdict__ = dict
63+ self.__inited = 1
64+
65+ def __getattr__(self, name):
66+ try:
67+ return self.__realdict__[name]
68+ except KeyError:
69+ for base in self.__bases__:
70+ try:
71+ return base.__getattr__(name)
72+ except AttributeError:
73+ pass
74+ raise AttributeError, name
75+
76+ def __setattr__(self, name, value):
77+ if not self.__inited:
78+ self.__dict__[name] = value
79+ else:
80+ self.__realdict__[name] = value
81+
82+ def __call__(self, *args, **kw):
83+ inst = self.__helper__()
84+ inst.__helperinit__(self)
85+ try:
86+ init = inst.__getattr__('__init__')
87+ except AttributeError:
88+ init = lambda: None
89+ apply(init, args, kw)
90+ return inst
91+
92+
93+Meta = MetaClass('Meta', (), {})
94+
95+
96+def _test():
97+ class C(Meta):
98+ def __init__(self, *args):
99+ print "__init__, args =", args
100+ def m1(self, x):
101+ print "m1(x=%r)" % (x,)
102+ print C
103+ x = C()
104+ print x
105+ x.m1(12)
106+ class D(C):
107+ def __getattr__(self, name):
108+ if name[:2] == '__': raise AttributeError, name
109+ return "getattr:%s" % name
110+ x = D()
111+ print x.foo
112+ print x._foo
113+## print x.__foo
114+## print x.__foo__
115+
116+
117+if __name__ == '__main__':
118+ _test()
sys/src/cmd/python/Demo/metaclasses/Simple.py+45−0
@@ -0,0 +1,45 @@
1+import types
2+
3+class Tracing:
4+ def __init__(self, name, bases, namespace):
5+ """Create a new class."""
6+ self.__name__ = name
7+ self.__bases__ = bases
8+ self.__namespace__ = namespace
9+ def __call__(self):
10+ """Create a new instance."""
11+ return Instance(self)
12+
13+class Instance:
14+ def __init__(self, klass):
15+ self.__klass__ = klass
16+ def __getattr__(self, name):
17+ try:
18+ value = self.__klass__.__namespace__[name]
19+ except KeyError:
20+ raise AttributeError, name
21+ if type(value) is not types.FunctionType:
22+ return value
23+ return BoundMethod(value, self)
24+
25+class BoundMethod:
26+ def __init__(self, function, instance):
27+ self.function = function
28+ self.instance = instance
29+ def __call__(self, *args):
30+ print "calling", self.function, "for", self.instance, "with", args
31+ return apply(self.function, (self.instance,) + args)
32+
33+Trace = Tracing('Trace', (), {})
34+
35+class MyTracedClass(Trace):
36+ def method1(self, a):
37+ self.a = a
38+ def method2(self):
39+ return self.a
40+
41+aninstance = MyTracedClass()
42+
43+aninstance.method1(10)
44+
45+print aninstance.method2()
sys/src/cmd/python/Demo/metaclasses/Synch.py+256−0
@@ -0,0 +1,256 @@
1+"""Synchronization metaclass.
2+
3+This metaclass makes it possible to declare synchronized methods.
4+
5+"""
6+
7+import thread
8+
9+# First we need to define a reentrant lock.
10+# This is generally useful and should probably be in a standard Python
11+# library module. For now, we in-line it.
12+
13+class Lock:
14+
15+ """Reentrant lock.
16+
17+ This is a mutex-like object which can be acquired by the same
18+ thread more than once. It keeps a reference count of the number
19+ of times it has been acquired by the same thread. Each acquire()
20+ call must be matched by a release() call and only the last
21+ release() call actually releases the lock for acquisition by
22+ another thread.
23+
24+ The implementation uses two locks internally:
25+
26+ __mutex is a short term lock used to protect the instance variables
27+ __wait is the lock for which other threads wait
28+
29+ A thread intending to acquire both locks should acquire __wait
30+ first.
31+
32+ The implementation uses two other instance variables, protected by
33+ locking __mutex:
34+
35+ __tid is the thread ID of the thread that currently has the lock
36+ __count is the number of times the current thread has acquired it
37+
38+ When the lock is released, __tid is None and __count is zero.
39+
40+ """
41+
42+ def __init__(self):
43+ """Constructor. Initialize all instance variables."""
44+ self.__mutex = thread.allocate_lock()
45+ self.__wait = thread.allocate_lock()
46+ self.__tid = None
47+ self.__count = 0
48+
49+ def acquire(self, flag=1):
50+ """Acquire the lock.
51+
52+ If the optional flag argument is false, returns immediately
53+ when it cannot acquire the __wait lock without blocking (it
54+ may still block for a little while in order to acquire the
55+ __mutex lock).
56+
57+ The return value is only relevant when the flag argument is
58+ false; it is 1 if the lock is acquired, 0 if not.
59+
60+ """
61+ self.__mutex.acquire()
62+ try:
63+ if self.__tid == thread.get_ident():
64+ self.__count = self.__count + 1
65+ return 1
66+ finally:
67+ self.__mutex.release()
68+ locked = self.__wait.acquire(flag)
69+ if not flag and not locked:
70+ return 0
71+ try:
72+ self.__mutex.acquire()
73+ assert self.__tid == None
74+ assert self.__count == 0
75+ self.__tid = thread.get_ident()
76+ self.__count = 1
77+ return 1
78+ finally:
79+ self.__mutex.release()
80+
81+ def release(self):
82+ """Release the lock.
83+
84+ If this thread doesn't currently have the lock, an assertion
85+ error is raised.
86+
87+ Only allow another thread to acquire the lock when the count
88+ reaches zero after decrementing it.
89+
90+ """
91+ self.__mutex.acquire()
92+ try:
93+ assert self.__tid == thread.get_ident()
94+ assert self.__count > 0
95+ self.__count = self.__count - 1
96+ if self.__count == 0:
97+ self.__tid = None
98+ self.__wait.release()
99+ finally:
100+ self.__mutex.release()
101+
102+
103+def _testLock():
104+
105+ done = []
106+
107+ def f2(lock, done=done):
108+ lock.acquire()
109+ print "f2 running in thread %d\n" % thread.get_ident(),
110+ lock.release()
111+ done.append(1)
112+
113+ def f1(lock, f2=f2, done=done):
114+ lock.acquire()
115+ print "f1 running in thread %d\n" % thread.get_ident(),
116+ try:
117+ f2(lock)
118+ finally:
119+ lock.release()
120+ done.append(1)
121+
122+ lock = Lock()
123+ lock.acquire()
124+ f1(lock) # Adds 2 to done
125+ lock.release()
126+
127+ lock.acquire()
128+
129+ thread.start_new_thread(f1, (lock,)) # Adds 2
130+ thread.start_new_thread(f1, (lock, f1)) # Adds 3
131+ thread.start_new_thread(f2, (lock,)) # Adds 1
132+ thread.start_new_thread(f2, (lock,)) # Adds 1
133+
134+ lock.release()
135+ import time
136+ while len(done) < 9:
137+ print len(done)
138+ time.sleep(0.001)
139+ print len(done)
140+
141+
142+# Now, the Locking metaclass is a piece of cake.
143+# As an example feature, methods whose name begins with exactly one
144+# underscore are not synchronized.
145+
146+from Meta import MetaClass, MetaHelper, MetaMethodWrapper
147+
148+class LockingMethodWrapper(MetaMethodWrapper):
149+ def __call__(self, *args, **kw):
150+ if self.__name__[:1] == '_' and self.__name__[1:] != '_':
151+ return apply(self.func, (self.inst,) + args, kw)
152+ self.inst.__lock__.acquire()
153+ try:
154+ return apply(self.func, (self.inst,) + args, kw)
155+ finally:
156+ self.inst.__lock__.release()
157+
158+class LockingHelper(MetaHelper):
159+ __methodwrapper__ = LockingMethodWrapper
160+ def __helperinit__(self, formalclass):
161+ MetaHelper.__helperinit__(self, formalclass)
162+ self.__lock__ = Lock()
163+
164+class LockingMetaClass(MetaClass):
165+ __helper__ = LockingHelper
166+
167+Locking = LockingMetaClass('Locking', (), {})
168+
169+def _test():
170+ # For kicks, take away the Locking base class and see it die
171+ class Buffer(Locking):
172+ def __init__(self, initialsize):
173+ assert initialsize > 0
174+ self.size = initialsize
175+ self.buffer = [None]*self.size
176+ self.first = self.last = 0
177+ def put(self, item):
178+ # Do we need to grow the buffer?
179+ if (self.last+1) % self.size != self.first:
180+ # Insert the new item
181+ self.buffer[self.last] = item
182+ self.last = (self.last+1) % self.size
183+ return
184+ # Double the buffer size
185+ # First normalize it so that first==0 and last==size-1
186+ print "buffer =", self.buffer
187+ print "first = %d, last = %d, size = %d" % (
188+ self.first, self.last, self.size)
189+ if self.first <= self.last:
190+ temp = self.buffer[self.first:self.last]
191+ else:
192+ temp = self.buffer[self.first:] + self.buffer[:self.last]
193+ print "temp =", temp
194+ self.buffer = temp + [None]*(self.size+1)
195+ self.first = 0
196+ self.last = self.size-1
197+ self.size = self.size*2
198+ print "Buffer size doubled to", self.size
199+ print "new buffer =", self.buffer
200+ print "first = %d, last = %d, size = %d" % (
201+ self.first, self.last, self.size)
202+ self.put(item) # Recursive call to test the locking
203+ def get(self):
204+ # Is the buffer empty?
205+ if self.first == self.last:
206+ raise EOFError # Avoid defining a new exception
207+ item = self.buffer[self.first]
208+ self.first = (self.first+1) % self.size
209+ return item
210+
211+ def producer(buffer, wait, n=1000):
212+ import time
213+ i = 0
214+ while i < n:
215+ print "put", i
216+ buffer.put(i)
217+ i = i+1
218+ print "Producer: done producing", n, "items"
219+ wait.release()
220+
221+ def consumer(buffer, wait, n=1000):
222+ import time
223+ i = 0
224+ tout = 0.001
225+ while i < n:
226+ try:
227+ x = buffer.get()
228+ if x != i:
229+ raise AssertionError, \
230+ "get() returned %s, expected %s" % (x, i)
231+ print "got", i
232+ i = i+1
233+ tout = 0.001
234+ except EOFError:
235+ time.sleep(tout)
236+ tout = tout*2
237+ print "Consumer: done consuming", n, "items"
238+ wait.release()
239+
240+ pwait = thread.allocate_lock()
241+ pwait.acquire()
242+ cwait = thread.allocate_lock()
243+ cwait.acquire()
244+ buffer = Buffer(1)
245+ n = 1000
246+ thread.start_new_thread(consumer, (buffer, cwait, n))
247+ thread.start_new_thread(producer, (buffer, pwait, n))
248+ pwait.acquire()
249+ print "Producer done"
250+ cwait.acquire()
251+ print "All done"
252+ print "buffer size ==", len(buffer.buffer)
253+
254+if __name__ == '__main__':
255+ _testLock()
256+ _test()
sys/src/cmd/python/Demo/metaclasses/Trace.py+144−0
@@ -0,0 +1,144 @@
1+"""Tracing metaclass.
2+
3+XXX This is very much a work in progress.
4+
5+"""
6+
7+import types, sys
8+
9+class TraceMetaClass:
10+ """Metaclass for tracing.
11+
12+ Classes defined using this metaclass have an automatic tracing
13+ feature -- by setting the __trace_output__ instance (or class)
14+ variable to a file object, trace messages about all calls are
15+ written to the file. The trace formatting can be changed by
16+ defining a suitable __trace_call__ method.
17+
18+ """
19+
20+ __inited = 0
21+
22+ def __init__(self, name, bases, dict):
23+ self.__name__ = name
24+ self.__bases__ = bases
25+ self.__dict = dict
26+ # XXX Can't define __dict__, alas
27+ self.__inited = 1
28+
29+ def __getattr__(self, name):
30+ try:
31+ return self.__dict[name]
32+ except KeyError:
33+ for base in self.__bases__:
34+ try:
35+ return base.__getattr__(name)
36+ except AttributeError:
37+ pass
38+ raise AttributeError, name
39+
40+ def __setattr__(self, name, value):
41+ if not self.__inited:
42+ self.__dict__[name] = value
43+ else:
44+ self.__dict[name] = value
45+
46+ def __call__(self, *args, **kw):
47+ inst = TracingInstance()
48+ inst.__meta_init__(self)
49+ try:
50+ init = inst.__getattr__('__init__')
51+ except AttributeError:
52+ init = lambda: None
53+ apply(init, args, kw)
54+ return inst
55+
56+ __trace_output__ = None
57+
58+class TracingInstance:
59+ """Helper class to represent an instance of a tracing class."""
60+
61+ def __trace_call__(self, fp, fmt, *args):
62+ fp.write((fmt+'\n') % args)
63+
64+ def __meta_init__(self, klass):
65+ self.__class = klass
66+
67+ def __getattr__(self, name):
68+ # Invoked for any attr not in the instance's __dict__
69+ try:
70+ raw = self.__class.__getattr__(name)
71+ except AttributeError:
72+ raise AttributeError, name
73+ if type(raw) != types.FunctionType:
74+ return raw
75+ # It's a function
76+ fullname = self.__class.__name__ + "." + name
77+ if not self.__trace_output__ or name == '__trace_call__':
78+ return NotTracingWrapper(fullname, raw, self)
79+ else:
80+ return TracingWrapper(fullname, raw, self)
81+
82+class NotTracingWrapper:
83+ def __init__(self, name, func, inst):
84+ self.__name__ = name
85+ self.func = func
86+ self.inst = inst
87+ def __call__(self, *args, **kw):
88+ return apply(self.func, (self.inst,) + args, kw)
89+
90+class TracingWrapper(NotTracingWrapper):
91+ def __call__(self, *args, **kw):
92+ self.inst.__trace_call__(self.inst.__trace_output__,
93+ "calling %s, inst=%s, args=%s, kw=%s",
94+ self.__name__, self.inst, args, kw)
95+ try:
96+ rv = apply(self.func, (self.inst,) + args, kw)
97+ except:
98+ t, v, tb = sys.exc_info()
99+ self.inst.__trace_call__(self.inst.__trace_output__,
100+ "returning from %s with exception %s: %s",
101+ self.__name__, t, v)
102+ raise t, v, tb
103+ else:
104+ self.inst.__trace_call__(self.inst.__trace_output__,
105+ "returning from %s with value %s",
106+ self.__name__, rv)
107+ return rv
108+
109+Traced = TraceMetaClass('Traced', (), {'__trace_output__': None})
110+
111+
112+def _test():
113+ global C, D
114+ class C(Traced):
115+ def __init__(self, x=0): self.x = x
116+ def m1(self, x): self.x = x
117+ def m2(self, y): return self.x + y
118+ __trace_output__ = sys.stdout
119+ class D(C):
120+ def m2(self, y): print "D.m2(%r)" % (y,); return C.m2(self, y)
121+ __trace_output__ = None
122+ x = C(4321)
123+ print x
124+ print x.x
125+ print x.m1(100)
126+ print x.m1(10)
127+ print x.m2(33)
128+ print x.m1(5)
129+ print x.m2(4000)
130+ print x.x
131+
132+ print C.__init__
133+ print C.m2
134+ print D.__init__
135+ print D.m2
136+
137+ y = D()
138+ print y
139+ print y.m1(10)
140+ print y.m2(100)
141+ print y.x
142+
143+if __name__ == '__main__':
144+ _test()
sys/src/cmd/python/Demo/metaclasses/index.html+605−0
@@ -0,0 +1,605 @@
1+<HTML>
2+
3+<HEAD>
4+<TITLE>Metaclasses in Python 1.5</TITLE>
5+</HEAD>
6+
7+<BODY BGCOLOR="FFFFFF">
8+
9+<H1>Metaclasses in Python 1.5</H1>
10+<H2>(A.k.a. The Killer Joke :-)</H2>
11+
12+<HR>
13+
14+(<i>Postscript:</i> reading this essay is probably not the best way to
15+understand the metaclass hook described here. See a <A
16+HREF="meta-vladimir.txt">message posted by Vladimir Marangozov</A>
17+which may give a gentler introduction to the matter. You may also
18+want to search Deja News for messages with "metaclass" in the subject
19+posted to comp.lang.python in July and August 1998.)
20+
21+<HR>
22+
23+<P>In previous Python releases (and still in 1.5), there is something
24+called the ``Don Beaudry hook'', after its inventor and champion.
25+This allows C extensions to provide alternate class behavior, thereby
26+allowing the Python class syntax to be used to define other class-like
27+entities. Don Beaudry has used this in his infamous <A
28+HREF="http://maigret.cog.brown.edu/pyutil/">MESS</A> package; Jim
29+Fulton has used it in his <A
30+HREF="http://www.digicool.com/releases/ExtensionClass/">Extension
31+Classes</A> package. (It has also been referred to as the ``Don
32+Beaudry <i>hack</i>,'' but that's a misnomer. There's nothing hackish
33+about it -- in fact, it is rather elegant and deep, even though
34+there's something dark to it.)
35+
36+<P>(On first reading, you may want to skip directly to the examples in
37+the section "Writing Metaclasses in Python" below, unless you want
38+your head to explode.)
39+
40+<P>
41+
42+<HR>
43+
44+<P>Documentation of the Don Beaudry hook has purposefully been kept
45+minimal, since it is a feature of incredible power, and is easily
46+abused. Basically, it checks whether the <b>type of the base
47+class</b> is callable, and if so, it is called to create the new
48+class.
49+
50+<P>Note the two indirection levels. Take a simple example:
51+
52+<PRE>
53+class B:
54+ pass
55+
56+class C(B):
57+ pass
58+</PRE>
59+
60+Take a look at the second class definition, and try to fathom ``the
61+type of the base class is callable.''
62+
63+<P>(Types are not classes, by the way. See questions 4.2, 4.19 and in
64+particular 6.22 in the <A
65+HREF="http://www.python.org/cgi-bin/faqw.py" >Python FAQ</A>
66+for more on this topic.)
67+
68+<P>
69+
70+<UL>
71+
72+<LI>The <b>base class</b> is B; this one's easy.<P>
73+
74+<LI>Since B is a class, its type is ``class''; so the <b>type of the
75+base class</b> is the type ``class''. This is also known as
76+types.ClassType, assuming the standard module <code>types</code> has
77+been imported.<P>
78+
79+<LI>Now is the type ``class'' <b>callable</b>? No, because types (in
80+core Python) are never callable. Classes are callable (calling a
81+class creates a new instance) but types aren't.<P>
82+
83+</UL>
84+
85+<P>So our conclusion is that in our example, the type of the base
86+class (of C) is not callable. So the Don Beaudry hook does not apply,
87+and the default class creation mechanism is used (which is also used
88+when there is no base class). In fact, the Don Beaudry hook never
89+applies when using only core Python, since the type of a core object
90+is never callable.
91+
92+<P>So what do Don and Jim do in order to use Don's hook? Write an
93+extension that defines at least two new Python object types. The
94+first would be the type for ``class-like'' objects usable as a base
95+class, to trigger Don's hook. This type must be made callable.
96+That's why we need a second type. Whether an object is callable
97+depends on its type. So whether a type object is callable depends on
98+<i>its</i> type, which is a <i>meta-type</i>. (In core Python there
99+is only one meta-type, the type ``type'' (types.TypeType), which is
100+the type of all type objects, even itself.) A new meta-type must
101+be defined that makes the type of the class-like objects callable.
102+(Normally, a third type would also be needed, the new ``instance''
103+type, but this is not an absolute requirement -- the new class type
104+could return an object of some existing type when invoked to create an
105+instance.)
106+
107+<P>Still confused? Here's a simple device due to Don himself to
108+explain metaclasses. Take a simple class definition; assume B is a
109+special class that triggers Don's hook:
110+
111+<PRE>
112+class C(B):
113+ a = 1
114+ b = 2
115+</PRE>
116+
117+This can be though of as equivalent to:
118+
119+<PRE>
120+C = type(B)('C', (B,), {'a': 1, 'b': 2})
121+</PRE>
122+
123+If that's too dense for you, here's the same thing written out using
124+temporary variables:
125+
126+<PRE>
127+creator = type(B) # The type of the base class
128+name = 'C' # The name of the new class
129+bases = (B,) # A tuple containing the base class(es)
130+namespace = {'a': 1, 'b': 2} # The namespace of the class statement
131+C = creator(name, bases, namespace)
132+</PRE>
133+
134+This is analogous to what happens without the Don Beaudry hook, except
135+that in that case the creator function is set to the default class
136+creator.
137+
138+<P>In either case, the creator is called with three arguments. The
139+first one, <i>name</i>, is the name of the new class (as given at the
140+top of the class statement). The <i>bases</i> argument is a tuple of
141+base classes (a singleton tuple if there's only one base class, like
142+the example). Finally, <i>namespace</i> is a dictionary containing
143+the local variables collected during execution of the class statement.
144+
145+<P>Note that the contents of the namespace dictionary is simply
146+whatever names were defined in the class statement. A little-known
147+fact is that when Python executes a class statement, it enters a new
148+local namespace, and all assignments and function definitions take
149+place in this namespace. Thus, after executing the following class
150+statement:
151+
152+<PRE>
153+class C:
154+ a = 1
155+ def f(s): pass
156+</PRE>
157+
158+the class namespace's contents would be {'a': 1, 'f': &lt;function f
159+...&gt;}.
160+
161+<P>But enough already about writing Python metaclasses in C; read the
162+documentation of <A
163+HREF="http://maigret.cog.brown.edu/pyutil/">MESS</A> or <A
164+HREF="http://www.digicool.com/papers/ExtensionClass.html" >Extension
165+Classes</A> for more information.
166+
167+<P>
168+
169+<HR>
170+
171+<H2>Writing Metaclasses in Python</H2>
172+
173+<P>In Python 1.5, the requirement to write a C extension in order to
174+write metaclasses has been dropped (though you can still do
175+it, of course). In addition to the check ``is the type of the base
176+class callable,'' there's a check ``does the base class have a
177+__class__ attribute.'' If so, it is assumed that the __class__
178+attribute refers to a class.
179+
180+<P>Let's repeat our simple example from above:
181+
182+<PRE>
183+class C(B):
184+ a = 1
185+ b = 2
186+</PRE>
187+
188+Assuming B has a __class__ attribute, this translates into:
189+
190+<PRE>
191+C = B.__class__('C', (B,), {'a': 1, 'b': 2})
192+</PRE>
193+
194+This is exactly the same as before except that instead of type(B),
195+B.__class__ is invoked. If you have read <A HREF=
196+"http://www.python.org/cgi-bin/faqw.py?req=show&file=faq06.022.htp"
197+>FAQ question 6.22</A> you will understand that while there is a big
198+technical difference between type(B) and B.__class__, they play the
199+same role at different abstraction levels. And perhaps at some point
200+in the future they will really be the same thing (at which point you
201+would be able to derive subclasses from built-in types).
202+
203+<P>At this point it may be worth mentioning that C.__class__ is the
204+same object as B.__class__, i.e., C's metaclass is the same as B's
205+metaclass. In other words, subclassing an existing class creates a
206+new (meta)inststance of the base class's metaclass.
207+
208+<P>Going back to the example, the class B.__class__ is instantiated,
209+passing its constructor the same three arguments that are passed to
210+the default class constructor or to an extension's metaclass:
211+<i>name</i>, <i>bases</i>, and <i>namespace</i>.
212+
213+<P>It is easy to be confused by what exactly happens when using a
214+metaclass, because we lose the absolute distinction between classes
215+and instances: a class is an instance of a metaclass (a
216+``metainstance''), but technically (i.e. in the eyes of the python
217+runtime system), the metaclass is just a class, and the metainstance
218+is just an instance. At the end of the class statement, the metaclass
219+whose metainstance is used as a base class is instantiated, yielding a
220+second metainstance (of the same metaclass). This metainstance is
221+then used as a (normal, non-meta) class; instantiation of the class
222+means calling the metainstance, and this will return a real instance.
223+And what class is that an instance of? Conceptually, it is of course
224+an instance of our metainstance; but in most cases the Python runtime
225+system will see it as an instance of a a helper class used by the
226+metaclass to implement its (non-meta) instances...
227+
228+<P>Hopefully an example will make things clearer. Let's presume we
229+have a metaclass MetaClass1. It's helper class (for non-meta
230+instances) is callled HelperClass1. We now (manually) instantiate
231+MetaClass1 once to get an empty special base class:
232+
233+<PRE>
234+BaseClass1 = MetaClass1("BaseClass1", (), {})
235+</PRE>
236+
237+We can now use BaseClass1 as a base class in a class statement:
238+
239+<PRE>
240+class MySpecialClass(BaseClass1):
241+ i = 1
242+ def f(s): pass
243+</PRE>
244+
245+At this point, MySpecialClass is defined; it is a metainstance of
246+MetaClass1 just like BaseClass1, and in fact the expression
247+``BaseClass1.__class__ == MySpecialClass.__class__ == MetaClass1''
248+yields true.
249+
250+<P>We are now ready to create instances of MySpecialClass. Let's
251+assume that no constructor arguments are required:
252+
253+<PRE>
254+x = MySpecialClass()
255+y = MySpecialClass()
256+print x.__class__, y.__class__
257+</PRE>
258+
259+The print statement shows that x and y are instances of HelperClass1.
260+How did this happen? MySpecialClass is an instance of MetaClass1
261+(``meta'' is irrelevant here); when an instance is called, its
262+__call__ method is invoked, and presumably the __call__ method defined
263+by MetaClass1 returns an instance of HelperClass1.
264+
265+<P>Now let's see how we could use metaclasses -- what can we do
266+with metaclasses that we can't easily do without them? Here's one
267+idea: a metaclass could automatically insert trace calls for all
268+method calls. Let's first develop a simplified example, without
269+support for inheritance or other ``advanced'' Python features (we'll
270+add those later).
271+
272+<PRE>
273+import types
274+
275+class Tracing:
276+ def __init__(self, name, bases, namespace):
277+ """Create a new class."""
278+ self.__name__ = name
279+ self.__bases__ = bases
280+ self.__namespace__ = namespace
281+ def __call__(self):
282+ """Create a new instance."""
283+ return Instance(self)
284+
285+class Instance:
286+ def __init__(self, klass):
287+ self.__klass__ = klass
288+ def __getattr__(self, name):
289+ try:
290+ value = self.__klass__.__namespace__[name]
291+ except KeyError:
292+ raise AttributeError, name
293+ if type(value) is not types.FunctionType:
294+ return value
295+ return BoundMethod(value, self)
296+
297+class BoundMethod:
298+ def __init__(self, function, instance):
299+ self.function = function
300+ self.instance = instance
301+ def __call__(self, *args):
302+ print "calling", self.function, "for", self.instance, "with", args
303+ return apply(self.function, (self.instance,) + args)
304+
305+Trace = Tracing('Trace', (), {})
306+
307+class MyTracedClass(Trace):
308+ def method1(self, a):
309+ self.a = a
310+ def method2(self):
311+ return self.a
312+
313+aninstance = MyTracedClass()
314+
315+aninstance.method1(10)
316+
317+print "the answer is %d" % aninstance.method2()
318+</PRE>
319+
320+Confused already? The intention is to read this from top down. The
321+Tracing class is the metaclass we're defining. Its structure is
322+really simple.
323+
324+<P>
325+
326+<UL>
327+
328+<LI>The __init__ method is invoked when a new Tracing instance is
329+created, e.g. the definition of class MyTracedClass later in the
330+example. It simply saves the class name, base classes and namespace
331+as instance variables.<P>
332+
333+<LI>The __call__ method is invoked when a Tracing instance is called,
334+e.g. the creation of aninstance later in the example. It returns an
335+instance of the class Instance, which is defined next.<P>
336+
337+</UL>
338+
339+<P>The class Instance is the class used for all instances of classes
340+built using the Tracing metaclass, e.g. aninstance. It has two
341+methods:
342+
343+<P>
344+
345+<UL>
346+
347+<LI>The __init__ method is invoked from the Tracing.__call__ method
348+above to initialize a new instance. It saves the class reference as
349+an instance variable. It uses a funny name because the user's
350+instance variables (e.g. self.a later in the example) live in the same
351+namespace.<P>
352+
353+<LI>The __getattr__ method is invoked whenever the user code
354+references an attribute of the instance that is not an instance
355+variable (nor a class variable; but except for __init__ and
356+__getattr__ there are no class variables). It will be called, for
357+example, when aninstance.method1 is referenced in the example, with
358+self set to aninstance and name set to the string "method1".<P>
359+
360+</UL>
361+
362+<P>The __getattr__ method looks the name up in the __namespace__
363+dictionary. If it isn't found, it raises an AttributeError exception.
364+(In a more realistic example, it would first have to look through the
365+base classes as well.) If it is found, there are two possibilities:
366+it's either a function or it isn't. If it's not a function, it is
367+assumed to be a class variable, and its value is returned. If it's a
368+function, we have to ``wrap'' it in instance of yet another helper
369+class, BoundMethod.
370+
371+<P>The BoundMethod class is needed to implement a familiar feature:
372+when a method is defined, it has an initial argument, self, which is
373+automatically bound to the relevant instance when it is called. For
374+example, aninstance.method1(10) is equivalent to method1(aninstance,
375+10). In the example if this call, first a temporary BoundMethod
376+instance is created with the following constructor call: temp =
377+BoundMethod(method1, aninstance); then this instance is called as
378+temp(10). After the call, the temporary instance is discarded.
379+
380+<P>
381+
382+<UL>
383+
384+<LI>The __init__ method is invoked for the constructor call
385+BoundMethod(method1, aninstance). It simply saves away its
386+arguments.<P>
387+
388+<LI>The __call__ method is invoked when the bound method instance is
389+called, as in temp(10). It needs to call method1(aninstance, 10).
390+However, even though self.function is now method1 and self.instance is
391+aninstance, it can't call self.function(self.instance, args) directly,
392+because it should work regardless of the number of arguments passed.
393+(For simplicity, support for keyword arguments has been omitted.)<P>
394+
395+</UL>
396+
397+<P>In order to be able to support arbitrary argument lists, the
398+__call__ method first constructs a new argument tuple. Conveniently,
399+because of the notation *args in __call__'s own argument list, the
400+arguments to __call__ (except for self) are placed in the tuple args.
401+To construct the desired argument list, we concatenate a singleton
402+tuple containing the instance with the args tuple: (self.instance,) +
403+args. (Note the trailing comma used to construct the singleton
404+tuple.) In our example, the resulting argument tuple is (aninstance,
405+10).
406+
407+<P>The intrinsic function apply() takes a function and an argument
408+tuple and calls the function for it. In our example, we are calling
409+apply(method1, (aninstance, 10)) which is equivalent to calling
410+method(aninstance, 10).
411+
412+<P>From here on, things should come together quite easily. The output
413+of the example code is something like this:
414+
415+<PRE>
416+calling &lt;function method1 at ae8d8&gt; for &lt;Instance instance at 95ab0&gt; with (10,)
417+calling &lt;function method2 at ae900&gt; for &lt;Instance instance at 95ab0&gt; with ()
418+the answer is 10
419+</PRE>
420+
421+<P>That was about the shortest meaningful example that I could come up
422+with. A real tracing metaclass (for example, <A
423+HREF="#Trace">Trace.py</A> discussed below) needs to be more
424+complicated in two dimensions.
425+
426+<P>First, it needs to support more advanced Python features such as
427+class variables, inheritance, __init__ methods, and keyword arguments.
428+
429+<P>Second, it needs to provide a more flexible way to handle the
430+actual tracing information; perhaps it should be possible to write
431+your own tracing function that gets called, perhaps it should be
432+possible to enable and disable tracing on a per-class or per-instance
433+basis, and perhaps a filter so that only interesting calls are traced;
434+it should also be able to trace the return value of the call (or the
435+exception it raised if an error occurs). Even the Trace.py example
436+doesn't support all these features yet.
437+
438+<P>
439+
440+<HR>
441+
442+<H1>Real-life Examples</H1>
443+
444+<P>Have a look at some very preliminary examples that I coded up to
445+teach myself how to write metaclasses:
446+
447+<DL>
448+
449+<DT><A HREF="Enum.py">Enum.py</A>
450+
451+<DD>This (ab)uses the class syntax as an elegant way to define
452+enumerated types. The resulting classes are never instantiated --
453+rather, their class attributes are the enumerated values. For
454+example:
455+
456+<PRE>
457+class Color(Enum):
458+ red = 1
459+ green = 2
460+ blue = 3
461+print Color.red
462+</PRE>
463+
464+will print the string ``Color.red'', while ``Color.red==1'' is true,
465+and ``Color.red + 1'' raise a TypeError exception.
466+
467+<P>
468+
469+<DT><A NAME=Trace></A><A HREF="Trace.py">Trace.py</A>
470+
471+<DD>The resulting classes work much like standard
472+classes, but by setting a special class or instance attribute
473+__trace_output__ to point to a file, all calls to the class's methods
474+are traced. It was a bit of a struggle to get this right. This
475+should probably redone using the generic metaclass below.
476+
477+<P>
478+
479+<DT><A HREF="Meta.py">Meta.py</A>
480+
481+<DD>A generic metaclass. This is an attempt at finding out how much
482+standard class behavior can be mimicked by a metaclass. The
483+preliminary answer appears to be that everything's fine as long as the
484+class (or its clients) don't look at the instance's __class__
485+attribute, nor at the class's __dict__ attribute. The use of
486+__getattr__ internally makes the classic implementation of __getattr__
487+hooks tough; we provide a similar hook _getattr_ instead.
488+(__setattr__ and __delattr__ are not affected.)
489+(XXX Hm. Could detect presence of __getattr__ and rename it.)
490+
491+<P>
492+
493+<DT><A HREF="Eiffel.py">Eiffel.py</A>
494+
495+<DD>Uses the above generic metaclass to implement Eiffel style
496+pre-conditions and post-conditions.
497+
498+<P>
499+
500+<DT><A HREF="Synch.py">Synch.py</A>
501+
502+<DD>Uses the above generic metaclass to implement synchronized
503+methods.
504+
505+<P>
506+
507+<DT><A HREF="Simple.py">Simple.py</A>
508+
509+<DD>The example module used above.
510+
511+<P>
512+
513+</DL>
514+
515+<P>A pattern seems to be emerging: almost all these uses of
516+metaclasses (except for Enum, which is probably more cute than useful)
517+mostly work by placing wrappers around method calls. An obvious
518+problem with that is that it's not easy to combine the features of
519+different metaclasses, while this would actually be quite useful: for
520+example, I wouldn't mind getting a trace from the test run of the
521+Synch module, and it would be interesting to add preconditions to it
522+as well. This needs more research. Perhaps a metaclass could be
523+provided that allows stackable wrappers...
524+
525+<P>
526+
527+<HR>
528+
529+<H2>Things You Could Do With Metaclasses</H2>
530+
531+<P>There are lots of things you could do with metaclasses. Most of
532+these can also be done with creative use of __getattr__, but
533+metaclasses make it easier to modify the attribute lookup behavior of
534+classes. Here's a partial list.
535+
536+<P>
537+
538+<UL>
539+
540+<LI>Enforce different inheritance semantics, e.g. automatically call
541+base class methods when a derived class overrides<P>
542+
543+<LI>Implement class methods (e.g. if the first argument is not named
544+'self')<P>
545+
546+<LI>Implement that each instance is initialized with <b>copies</b> of
547+all class variables<P>
548+
549+<LI>Implement a different way to store instance variables (e.g. in a
550+list kept outside the instance but indexed by the instance's id())<P>
551+
552+<LI>Automatically wrap or trap all or certain methods
553+
554+<UL>
555+
556+<LI>for tracing
557+
558+<LI>for precondition and postcondition checking
559+
560+<LI>for synchronized methods
561+
562+<LI>for automatic value caching
563+
564+</UL>
565+<P>
566+
567+<LI>When an attribute is a parameterless function, call it on
568+reference (to mimic it being an instance variable); same on assignment<P>
569+
570+<LI>Instrumentation: see how many times various attributes are used<P>
571+
572+<LI>Different semantics for __setattr__ and __getattr__ (e.g. disable
573+them when they are being used recursively)<P>
574+
575+<LI>Abuse class syntax for other things<P>
576+
577+<LI>Experiment with automatic type checking<P>
578+
579+<LI>Delegation (or acquisition)<P>
580+
581+<LI>Dynamic inheritance patterns<P>
582+
583+<LI>Automatic caching of methods<P>
584+
585+</UL>
586+
587+<P>
588+
589+<HR>
590+
591+<H4>Credits</H4>
592+
593+<P>Many thanks to David Ascher and Donald Beaudry for their comments
594+on earlier draft of this paper. Also thanks to Matt Conway and Tommy
595+Burnette for putting a seed for the idea of metaclasses in my
596+mind, nearly three years ago, even though at the time my response was
597+``you can do that with __getattr__ hooks...'' :-)
598+
599+<P>
600+
601+<HR>
602+
603+</BODY>
604+
605+</HTML>
sys/src/cmd/python/Demo/metaclasses/meta-vladimir.txt+256−0
@@ -0,0 +1,256 @@
1+Subject: Re: The metaclass saga using Python
2+From: Vladimir Marangozov <Vladimir.Marangozov@imag.fr>
3+To: tim_one@email.msn.com (Tim Peters)
4+Cc: python-list@cwi.nl
5+Date: Wed, 5 Aug 1998 15:59:06 +0200 (DFT)
6+
7+[Tim]
8+>
9+> building-on-examples-tends-to-prevent-abstract-thrashing-ly y'rs - tim
10+>
11+
12+OK, I stand corrected. I understand that anybody's interpretation of
13+the meta-class concept is likely to be difficult to digest by others.
14+
15+Here's another try, expressing the same thing, but using the Python
16+programming model, examples and, perhaps, more popular terms.
17+
18+1. Classes.
19+
20+ This is pure Python of today. Sorry about the tutorial, but it is
21+ meant to illustrate the second part, which is the one we're
22+ interested in and which will follow the same development scenario.
23+ Besides, newbies are likely to understand that the discussion is
24+ affordable even for them :-)
25+
26+ a) Class definition
27+
28+ A class is meant to define the common properties of a set of objects.
29+ A class is a "package" of properties. The assembly of properties
30+ in a class package is sometimes called a class structure (which isn't
31+ always appropriate).
32+
33+ >>> class A:
34+ attr1 = "Hello" # an attribute of A
35+ def method1(self, *args): pass # method1 of A
36+ def method2(self, *args): pass # method2 of A
37+ >>>
38+
39+ So far, we defined the structure of the class A. The class A is
40+ of type <class>. We can check this by asking Python: "what is A?"
41+
42+ >>> A # What is A?
43+ <class __main__.A at 2023e360>
44+
45+ b) Class instantiation
46+
47+ Creating an object with the properties defined in the class A is
48+ called instantiation of the class A. After an instantiation of A, we
49+ obtain a new object, called an instance, which has the properties
50+ packaged in the class A.
51+
52+ >>> a = A() # 'a' is the 1st instance of A
53+ >>> a # What is 'a'?
54+ <__main__.A instance at 2022b9d0>
55+
56+ >>> b = A() # 'b' is another instance of A
57+ >>> b # What is 'b'?
58+ <__main__.A instance at 2022b9c0>
59+
60+ The objects, 'a' and 'b', are of type <instance> and they both have
61+ the same properties. Note, that 'a' and 'b' are different objects.
62+ (their adresses differ). This is a bit hard to see, so let's ask Python:
63+
64+ >>> a == b # Is 'a' the same object as 'b'?
65+ 0 # No.
66+
67+ Instance objects have one more special property, indicating the class
68+ they are an instance of. This property is named __class__.
69+
70+ >>> a.__class__ # What is the class of 'a'?
71+ <class __main__.A at 2023e360> # 'a' is an instance of A
72+ >>> b.__class__ # What is the class of 'b'?
73+ <class __main__.A at 2023e360> # 'b' is an instance of A
74+ >>> a.__class__ == b.__class__ # Is it really the same class A?
75+ 1 # Yes.
76+
77+ c) Class inheritance (class composition and specialization)
78+
79+ Classes can be defined in terms of other existing classes (and only
80+ classes! -- don't bug me on this now). Thus, we can compose property
81+ packages and create new ones. We reuse the property set defined
82+ in a class by defining a new class, which "inherits" from the former.
83+ In other words, a class B which inherits from the class A, inherits
84+ the properties defined in A, or, B inherits the structure of A.
85+
86+ In the same time, at the definition of the new class B, we can enrich
87+ the inherited set of properties by adding new ones and/or modify some
88+ of the inherited properties.
89+
90+ >>> class B(A): # B inherits A's properties
91+ attr2 = "World" # additional attr2
92+ def method2(self, arg1): pass # method2 is redefined
93+ def method3(self, *args): pass # additional method3
94+
95+ >>> B # What is B?
96+ <class __main__.B at 2023e500>
97+ >>> B == A # Is B the same class as A?
98+ 0 # No.
99+
100+ Classes define one special property, indicating whether a class
101+ inherits the properties of another class. This property is called
102+ __bases__ and it contains a list (a tuple) of the classes the new
103+ class inherits from. The classes from which a class is inheriting the
104+ properties are called superclasses (in Python, we call them also --
105+ base classes).
106+
107+ >>> A.__bases__ # Does A have any superclasses?
108+ () # No.
109+ >>> B.__bases__ # Does B have any superclasses?
110+ (<class __main__.A at 2023e360>,) # Yes. It has one superclass.
111+ >>> B.__bases__[0] == A # Is it really the class A?
112+ 1 # Yes, it is.
113+
114+--------
115+
116+ Congratulations on getting this far! This was the hard part.
117+ Now, let's continue with the easy one.
118+
119+--------
120+
121+2. Meta-classes
122+
123+ You have to admit, that an anonymous group of Python wizards are
124+ not satisfied with the property packaging facilities presented above.
125+ They say, that the Real-World bugs them with problems that cannot be
126+ modelled successfully with classes. Or, that the way classes are
127+ implemented in Python and the way classes and instances behave at
128+ runtime isn't always appropriate for reproducing the Real-World's
129+ behavior in a way that satisfies them.
130+
131+ Hence, what they want is the following:
132+
133+ a) leave objects as they are (instances of classes)
134+ b) leave classes as they are (property packages and object creators)
135+
136+ BUT, at the same time:
137+
138+ c) consider classes as being instances of mysterious objects.
139+ d) label mysterious objects "meta-classes".
140+
141+ Easy, eh?
142+
143+ You may ask: "Why on earth do they want to do that?".
144+ They answer: "Poor soul... Go and see how cruel the Real-World is!".
145+ You - fuzzy: "OK, will do!"
146+
147+ And here we go for another round of what I said in section 1 -- Classes.
148+
149+ However, be warned! The features we're going to talk about aren't fully
150+ implemented yet, because the Real-World don't let wizards to evaluate
151+ precisely how cruel it is, so the features are still highly-experimental.
152+
153+ a) Meta-class definition
154+
155+ A meta-class is meant to define the common properties of a set of
156+ classes. A meta-class is a "package" of properties. The assembly
157+ of properties in a meta-class package is sometimes called a meta-class
158+ structure (which isn't always appropriate).
159+
160+ In Python, a meta-class definition would have looked like this:
161+
162+ >>> metaclass M:
163+ attr1 = "Hello" # an attribute of M
164+ def method1(self, *args): pass # method1 of M
165+ def method2(self, *args): pass # method2 of M
166+ >>>
167+
168+ So far, we defined the structure of the meta-class M. The meta-class
169+ M is of type <metaclass>. We cannot check this by asking Python, but
170+ if we could, it would have answered:
171+
172+ >>> M # What is M?
173+ <metaclass __main__.M at 2023e4e0>
174+
175+ b) Meta-class instantiation
176+
177+ Creating an object with the properties defined in the meta-class M is
178+ called instantiation of the meta-class M. After an instantiation of M,
179+ we obtain a new object, called an class, but now it is called also
180+ a meta-instance, which has the properties packaged in the meta-class M.
181+
182+ In Python, instantiating a meta-class would have looked like this:
183+
184+ >>> A = M() # 'A' is the 1st instance of M
185+ >>> A # What is 'A'?
186+ <class __main__.A at 2022b9d0>
187+
188+ >>> B = M() # 'B' is another instance of M
189+ >>> B # What is 'B'?
190+ <class __main__.B at 2022b9c0>
191+
192+ The metaclass-instances, A and B, are of type <class> and they both
193+ have the same properties. Note, that A and B are different objects.
194+ (their adresses differ). This is a bit hard to see, but if it was
195+ possible to ask Python, it would have answered:
196+
197+ >>> A == B # Is A the same class as B?
198+ 0 # No.
199+
200+ Class objects have one more special property, indicating the meta-class
201+ they are an instance of. This property is named __metaclass__.
202+
203+ >>> A.__metaclass__ # What is the meta-class of A?
204+ <metaclass __main__.M at 2023e4e0> # A is an instance of M
205+ >>> A.__metaclass__ # What is the meta-class of B?
206+ <metaclass __main__.M at 2023e4e0> # B is an instance of M
207+ >>> A.__metaclass__ == B.__metaclass__ # Is it the same meta-class M?
208+ 1 # Yes.
209+
210+ c) Meta-class inheritance (meta-class composition and specialization)
211+
212+ Meta-classes can be defined in terms of other existing meta-classes
213+ (and only meta-classes!). Thus, we can compose property packages and
214+ create new ones. We reuse the property set defined in a meta-class by
215+ defining a new meta-class, which "inherits" from the former.
216+ In other words, a meta-class N which inherits from the meta-class M,
217+ inherits the properties defined in M, or, N inherits the structure of M.
218+
219+ In the same time, at the definition of the new meta-class N, we can
220+ enrich the inherited set of properties by adding new ones and/or modify
221+ some of the inherited properties.
222+
223+ >>> metaclass N(M): # N inherits M's properties
224+ attr2 = "World" # additional attr2
225+ def method2(self, arg1): pass # method2 is redefined
226+ def method3(self, *args): pass # additional method3
227+
228+ >>> N # What is N?
229+ <metaclass __main__.N at 2023e500>
230+ >>> N == M # Is N the same meta-class as M?
231+ 0 # No.
232+
233+ Meta-classes define one special property, indicating whether a
234+ meta-class inherits the properties of another meta-class. This property
235+ is called __metabases__ and it contains a list (a tuple) of the
236+ meta-classes the new meta-class inherits from. The meta-classes from
237+ which a meta-class is inheriting the properties are called
238+ super-meta-classes (in Python, we call them also -- super meta-bases).
239+
240+ >>> M.__metabases__ # Does M have any supermetaclasses?
241+ () # No.
242+ >>> N.__metabases__ # Does N have any supermetaclasses?
243+ (<metaclass __main__.M at 2023e360>,) # Yes. It has a supermetaclass.
244+ >>> N.__metabases__[0] == M # Is it really the meta-class M?
245+ 1 # Yes, it is.
246+
247+--------
248+
249+ Triple congratulations on getting this far!
250+ Now you know everything about meta-classes and the Real-World!
251+
252+<unless-wizards-want-meta-classes-be-instances-of-mysterious-objects!>
253+
254+--
255+ Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr
256+http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252
sys/src/cmd/python/Demo/newmetaclasses/Eiffel.py+141−0
@@ -0,0 +1,141 @@
1+"""Support Eiffel-style preconditions and postconditions."""
2+
3+from new import function
4+
5+class EiffelBaseMetaClass(type):
6+
7+ def __new__(meta, name, bases, dict):
8+ meta.convert_methods(dict)
9+ return super(EiffelBaseMetaClass, meta).__new__(meta, name, bases,
10+ dict)
11+
12+ @classmethod
13+ def convert_methods(cls, dict):
14+ """Replace functions in dict with EiffelMethod wrappers.
15+
16+ The dict is modified in place.
17+
18+ If a method ends in _pre or _post, it is removed from the dict
19+ regardless of whether there is a corresponding method.
20+ """
21+ # find methods with pre or post conditions
22+ methods = []
23+ for k, v in dict.iteritems():
24+ if k.endswith('_pre') or k.endswith('_post'):
25+ assert isinstance(v, function)
26+ elif isinstance(v, function):
27+ methods.append(k)
28+ for m in methods:
29+ pre = dict.get("%s_pre" % m)
30+ post = dict.get("%s_post" % m)
31+ if pre or post:
32+ dict[k] = cls.make_eiffel_method(dict[m], pre, post)
33+
34+class EiffelMetaClass1(EiffelBaseMetaClass):
35+ # an implementation of the "eiffel" meta class that uses nested functions
36+
37+ @staticmethod
38+ def make_eiffel_method(func, pre, post):
39+ def method(self, *args, **kwargs):
40+ if pre:
41+ pre(self, *args, **kwargs)
42+ x = func(self, *args, **kwargs)
43+ if post:
44+ post(self, x, *args, **kwargs)
45+ return x
46+
47+ if func.__doc__:
48+ method.__doc__ = func.__doc__
49+
50+ return method
51+
52+class EiffelMethodWrapper:
53+
54+ def __init__(self, inst, descr):
55+ self._inst = inst
56+ self._descr = descr
57+
58+ def __call__(self, *args, **kwargs):
59+ return self._descr.callmethod(self._inst, args, kwargs)
60+
61+class EiffelDescriptor(object):
62+
63+ def __init__(self, func, pre, post):
64+ self._func = func
65+ self._pre = pre
66+ self._post = post
67+
68+ self.__name__ = func.__name__
69+ self.__doc__ = func.__doc__
70+
71+ def __get__(self, obj, cls):
72+ return EiffelMethodWrapper(obj, self)
73+
74+ def callmethod(self, inst, args, kwargs):
75+ if self._pre:
76+ self._pre(inst, *args, **kwargs)
77+ x = self._func(inst, *args, **kwargs)
78+ if self._post:
79+ self._post(inst, x, *args, **kwargs)
80+ return x
81+
82+class EiffelMetaClass2(EiffelBaseMetaClass):
83+ # an implementation of the "eiffel" meta class that uses descriptors
84+
85+ make_eiffel_method = EiffelDescriptor
86+
87+def _test(metaclass):
88+ class Eiffel:
89+ __metaclass__ = metaclass
90+
91+ class Test(Eiffel):
92+
93+ def m(self, arg):
94+ """Make it a little larger"""
95+ return arg + 1
96+
97+ def m2(self, arg):
98+ """Make it a little larger"""
99+ return arg + 1
100+
101+ def m2_pre(self, arg):
102+ assert arg > 0
103+
104+ def m2_post(self, result, arg):
105+ assert result > arg
106+
107+ class Sub(Test):
108+ def m2(self, arg):
109+ return arg**2
110+ def m2_post(self, Result, arg):
111+ super(Sub, self).m2_post(Result, arg)
112+ assert Result < 100
113+
114+ t = Test()
115+ t.m(1)
116+ t.m2(1)
117+ try:
118+ t.m2(0)
119+ except AssertionError:
120+ pass
121+ else:
122+ assert False
123+
124+ s = Sub()
125+ try:
126+ s.m2(1)
127+ except AssertionError:
128+ pass # result == arg
129+ else:
130+ assert False
131+ try:
132+ s.m2(10)
133+ except AssertionError:
134+ pass # result == 100
135+ else:
136+ assert False
137+ s.m2(5)
138+
139+if __name__ == "__main__":
140+ _test(EiffelMetaClass1)
141+ _test(EiffelMetaClass2)
sys/src/cmd/python/Demo/newmetaclasses/Enum.py+177−0
@@ -0,0 +1,177 @@
1+"""Enumeration metaclass."""
2+
3+class EnumMetaclass(type):
4+ """Metaclass for enumeration.
5+
6+ To define your own enumeration, do something like
7+
8+ class Color(Enum):
9+ red = 1
10+ green = 2
11+ blue = 3
12+
13+ Now, Color.red, Color.green and Color.blue behave totally
14+ different: they are enumerated values, not integers.
15+
16+ Enumerations cannot be instantiated; however they can be
17+ subclassed.
18+ """
19+
20+ def __init__(cls, name, bases, dict):
21+ super(EnumMetaclass, cls).__init__(name, bases, dict)
22+ cls._members = []
23+ for attr in dict.keys():
24+ if not (attr.startswith('__') and attr.endswith('__')):
25+ enumval = EnumInstance(name, attr, dict[attr])
26+ setattr(cls, attr, enumval)
27+ cls._members.append(attr)
28+
29+ def __getattr__(cls, name):
30+ if name == "__members__":
31+ return cls._members
32+ raise AttributeError, name
33+
34+ def __repr__(cls):
35+ s1 = s2 = ""
36+ enumbases = [base.__name__ for base in cls.__bases__
37+ if isinstance(base, EnumMetaclass) and not base is Enum]
38+ if enumbases:
39+ s1 = "(%s)" % ", ".join(enumbases)
40+ enumvalues = ["%s: %d" % (val, getattr(cls, val))
41+ for val in cls._members]
42+ if enumvalues:
43+ s2 = ": {%s}" % ", ".join(enumvalues)
44+ return "%s%s%s" % (cls.__name__, s1, s2)
45+
46+class FullEnumMetaclass(EnumMetaclass):
47+ """Metaclass for full enumerations.
48+
49+ A full enumeration displays all the values defined in base classes.
50+ """
51+
52+ def __init__(cls, name, bases, dict):
53+ super(FullEnumMetaclass, cls).__init__(name, bases, dict)
54+ for obj in cls.__mro__:
55+ if isinstance(obj, EnumMetaclass):
56+ for attr in obj._members:
57+ # XXX inefficient
58+ if not attr in cls._members:
59+ cls._members.append(attr)
60+
61+class EnumInstance(int):
62+ """Class to represent an enumeration value.
63+
64+ EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
65+ like the integer 12 when compared, but doesn't support arithmetic.
66+
67+ XXX Should it record the actual enumeration rather than just its
68+ name?
69+ """
70+
71+ def __new__(cls, classname, enumname, value):
72+ return int.__new__(cls, value)
73+
74+ def __init__(self, classname, enumname, value):
75+ self.__classname = classname
76+ self.__enumname = enumname
77+
78+ def __repr__(self):
79+ return "EnumInstance(%s, %s, %d)" % (self.__classname, self.__enumname,
80+ self)
81+
82+ def __str__(self):
83+ return "%s.%s" % (self.__classname, self.__enumname)
84+
85+class Enum:
86+ __metaclass__ = EnumMetaclass
87+
88+class FullEnum:
89+ __metaclass__ = FullEnumMetaclass
90+
91+def _test():
92+
93+ class Color(Enum):
94+ red = 1
95+ green = 2
96+ blue = 3
97+
98+ print Color.red
99+
100+ print repr(Color.red)
101+ print Color.red == Color.red
102+ print Color.red == Color.blue
103+ print Color.red == 1
104+ print Color.red == 2
105+
106+ class ExtendedColor(Color):
107+ white = 0
108+ orange = 4
109+ yellow = 5
110+ purple = 6
111+ black = 7
112+
113+ print ExtendedColor.orange
114+ print ExtendedColor.red
115+
116+ print Color.red == ExtendedColor.red
117+
118+ class OtherColor(Enum):
119+ white = 4
120+ blue = 5
121+
122+ class MergedColor(Color, OtherColor):
123+ pass
124+
125+ print MergedColor.red
126+ print MergedColor.white
127+
128+ print Color
129+ print ExtendedColor
130+ print OtherColor
131+ print MergedColor
132+
133+def _test2():
134+
135+ class Color(FullEnum):
136+ red = 1
137+ green = 2
138+ blue = 3
139+
140+ print Color.red
141+
142+ print repr(Color.red)
143+ print Color.red == Color.red
144+ print Color.red == Color.blue
145+ print Color.red == 1
146+ print Color.red == 2
147+
148+ class ExtendedColor(Color):
149+ white = 0
150+ orange = 4
151+ yellow = 5
152+ purple = 6
153+ black = 7
154+
155+ print ExtendedColor.orange
156+ print ExtendedColor.red
157+
158+ print Color.red == ExtendedColor.red
159+
160+ class OtherColor(FullEnum):
161+ white = 4
162+ blue = 5
163+
164+ class MergedColor(Color, OtherColor):
165+ pass
166+
167+ print MergedColor.red
168+ print MergedColor.white
169+
170+ print Color
171+ print ExtendedColor
172+ print OtherColor
173+ print MergedColor
174+
175+if __name__ == '__main__':
176+ _test()
177+ _test2()
sys/src/cmd/python/Demo/parser/FILES+6−0
@@ -0,0 +1,6 @@
1+Demo/parser
2+Doc/libparser.tex
3+Lib/AST.py
4+Lib/symbol.py
5+Lib/token.py
6+Modules/parsermodule.c
sys/src/cmd/python/Demo/parser/README+31−0
@@ -0,0 +1,31 @@
1+These files are from the large example of using the `parser' module. Refer
2+to the Python Library Reference for more information.
3+
4+It also contains examples for the AST parser.
5+
6+Files:
7+------
8+
9+ FILES -- list of files associated with the parser module.
10+
11+ README -- this file.
12+
13+ example.py -- module that uses the `parser' module to extract
14+ information from the parse tree of Python source
15+ code.
16+
17+ docstring.py -- sample source file containing only a module docstring.
18+
19+ simple.py -- sample source containing a "short form" definition.
20+
21+ source.py -- sample source code used to demonstrate ability to
22+ handle nested constructs easily using the functions
23+ and classes in example.py.
24+
25+ test_parser.py program to put the parser module through its paces.
26+
27+ unparse.py AST (2.5) based example to recreate source code
28+ from an AST. This is incomplete; contributions
29+ are welcome.
30+
31+Enjoy!
sys/src/cmd/python/Demo/parser/docstring.py+2−0
@@ -0,0 +1,2 @@
1+"""Some documentation.
2+"""
sys/src/cmd/python/Demo/parser/example.py+190−0
@@ -0,0 +1,190 @@
1+"""Simple code to extract class & function docstrings from a module.
2+
3+This code is used as an example in the library reference manual in the
4+section on using the parser module. Refer to the manual for a thorough
5+discussion of the operation of this code.
6+"""
7+
8+import os
9+import parser
10+import symbol
11+import token
12+import types
13+
14+from types import ListType, TupleType
15+
16+
17+def get_docs(fileName):
18+ """Retrieve information from the parse tree of a source file.
19+
20+ fileName
21+ Name of the file to read Python source code from.
22+ """
23+ source = open(fileName).read()
24+ basename = os.path.basename(os.path.splitext(fileName)[0])
25+ ast = parser.suite(source)
26+ return ModuleInfo(ast.totuple(), basename)
27+
28+
29+class SuiteInfoBase:
30+ _docstring = ''
31+ _name = ''
32+
33+ def __init__(self, tree = None):
34+ self._class_info = {}
35+ self._function_info = {}
36+ if tree:
37+ self._extract_info(tree)
38+
39+ def _extract_info(self, tree):
40+ # extract docstring
41+ if len(tree) == 2:
42+ found, vars = match(DOCSTRING_STMT_PATTERN[1], tree[1])
43+ else:
44+ found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
45+ if found:
46+ self._docstring = eval(vars['docstring'])
47+ # discover inner definitions
48+ for node in tree[1:]:
49+ found, vars = match(COMPOUND_STMT_PATTERN, node)
50+ if found:
51+ cstmt = vars['compound']
52+ if cstmt[0] == symbol.funcdef:
53+ name = cstmt[2][1]
54+ self._function_info[name] = FunctionInfo(cstmt)
55+ elif cstmt[0] == symbol.classdef:
56+ name = cstmt[2][1]
57+ self._class_info[name] = ClassInfo(cstmt)
58+
59+ def get_docstring(self):
60+ return self._docstring
61+
62+ def get_name(self):
63+ return self._name
64+
65+ def get_class_names(self):
66+ return self._class_info.keys()
67+
68+ def get_class_info(self, name):
69+ return self._class_info[name]
70+
71+ def __getitem__(self, name):
72+ try:
73+ return self._class_info[name]
74+ except KeyError:
75+ return self._function_info[name]
76+
77+
78+class SuiteFuncInfo:
79+ # Mixin class providing access to function names and info.
80+
81+ def get_function_names(self):
82+ return self._function_info.keys()
83+
84+ def get_function_info(self, name):
85+ return self._function_info[name]
86+
87+
88+class FunctionInfo(SuiteInfoBase, SuiteFuncInfo):
89+ def __init__(self, tree = None):
90+ self._name = tree[2][1]
91+ SuiteInfoBase.__init__(self, tree and tree[-1] or None)
92+
93+
94+class ClassInfo(SuiteInfoBase):
95+ def __init__(self, tree = None):
96+ self._name = tree[2][1]
97+ SuiteInfoBase.__init__(self, tree and tree[-1] or None)
98+
99+ def get_method_names(self):
100+ return self._function_info.keys()
101+
102+ def get_method_info(self, name):
103+ return self._function_info[name]
104+
105+
106+class ModuleInfo(SuiteInfoBase, SuiteFuncInfo):
107+ def __init__(self, tree = None, name = "<string>"):
108+ self._name = name
109+ SuiteInfoBase.__init__(self, tree)
110+ if tree:
111+ found, vars = match(DOCSTRING_STMT_PATTERN, tree[1])
112+ if found:
113+ self._docstring = vars["docstring"]
114+
115+
116+def match(pattern, data, vars=None):
117+ """Match `data' to `pattern', with variable extraction.
118+
119+ pattern
120+ Pattern to match against, possibly containing variables.
121+
122+ data
123+ Data to be checked and against which variables are extracted.
124+
125+ vars
126+ Dictionary of variables which have already been found. If not
127+ provided, an empty dictionary is created.
128+
129+ The `pattern' value may contain variables of the form ['varname'] which
130+ are allowed to match anything. The value that is matched is returned as
131+ part of a dictionary which maps 'varname' to the matched value. 'varname'
132+ is not required to be a string object, but using strings makes patterns
133+ and the code which uses them more readable.
134+
135+ This function returns two values: a boolean indicating whether a match
136+ was found and a dictionary mapping variable names to their associated
137+ values.
138+ """
139+ if vars is None:
140+ vars = {}
141+ if type(pattern) is ListType: # 'variables' are ['varname']
142+ vars[pattern[0]] = data
143+ return 1, vars
144+ if type(pattern) is not TupleType:
145+ return (pattern == data), vars
146+ if len(data) != len(pattern):
147+ return 0, vars
148+ for pattern, data in map(None, pattern, data):
149+ same, vars = match(pattern, data, vars)
150+ if not same:
151+ break
152+ return same, vars
153+
154+
155+# This pattern identifies compound statements, allowing them to be readily
156+# differentiated from simple statements.
157+#
158+COMPOUND_STMT_PATTERN = (
159+ symbol.stmt,
160+ (symbol.compound_stmt, ['compound'])
161+ )
162+
163+
164+# This pattern will match a 'stmt' node which *might* represent a docstring;
165+# docstrings require that the statement which provides the docstring be the
166+# first statement in the class or function, which this pattern does not check.
167+#
168+DOCSTRING_STMT_PATTERN = (
169+ symbol.stmt,
170+ (symbol.simple_stmt,
171+ (symbol.small_stmt,
172+ (symbol.expr_stmt,
173+ (symbol.testlist,
174+ (symbol.test,
175+ (symbol.and_test,
176+ (symbol.not_test,
177+ (symbol.comparison,
178+ (symbol.expr,
179+ (symbol.xor_expr,
180+ (symbol.and_expr,
181+ (symbol.shift_expr,
182+ (symbol.arith_expr,
183+ (symbol.term,
184+ (symbol.factor,
185+ (symbol.power,
186+ (symbol.atom,
187+ (token.STRING, ['docstring'])
188+ )))))))))))))))),
189+ (token.NEWLINE, '')
190+ ))
sys/src/cmd/python/Demo/parser/simple.py+1−0
@@ -0,0 +1 @@
1+def f(): "maybe a docstring"
sys/src/cmd/python/Demo/parser/source.py+27−0
@@ -0,0 +1,27 @@
1+"""Exmaple file to be parsed for the parsermodule example.
2+
3+The classes and functions in this module exist only to exhibit the ability
4+of the handling information extraction from nested definitions using parse
5+trees. They shouldn't interest you otherwise!
6+"""
7+
8+class Simple:
9+ "This class does very little."
10+
11+ def method(self):
12+ "This method does almost nothing."
13+ return 1
14+
15+ class Nested:
16+ "This is a nested class."
17+
18+ def nested_method(self):
19+ "Method of Nested class."
20+ def nested_function():
21+ "Function in method of Nested class."
22+ pass
23+ return nested_function
24+
25+def function():
26+ "This function lives at the module level."
27+ return 0
sys/src/cmd/python/Demo/parser/test_parser.py+48−0
@@ -0,0 +1,48 @@
1+#! /usr/bin/env python
2+# (Force the script to use the latest build.)
3+#
4+# test_parser.py
5+
6+import parser, traceback
7+
8+_numFailed = 0
9+
10+def testChunk(t, fileName):
11+ global _numFailed
12+ print '----', fileName,
13+ try:
14+ ast = parser.suite(t)
15+ tup = parser.ast2tuple(ast)
16+ # this discards the first AST; a huge memory savings when running
17+ # against a large source file like Tkinter.py.
18+ ast = None
19+ new = parser.tuple2ast(tup)
20+ except parser.ParserError, err:
21+ print
22+ print 'parser module raised exception on input file', fileName + ':'
23+ traceback.print_exc()
24+ _numFailed = _numFailed + 1
25+ else:
26+ if tup != parser.ast2tuple(new):
27+ print
28+ print 'parser module failed on input file', fileName
29+ _numFailed = _numFailed + 1
30+ else:
31+ print 'o.k.'
32+
33+def testFile(fileName):
34+ t = open(fileName).read()
35+ testChunk(t, fileName)
36+
37+def test():
38+ import sys
39+ args = sys.argv[1:]
40+ if not args:
41+ import glob
42+ args = glob.glob("*.py")
43+ args.sort()
44+ map(testFile, args)
45+ sys.exit(_numFailed != 0)
46+
47+if __name__ == '__main__':
48+ test()
sys/src/cmd/python/Demo/parser/texipre.dat+100−0
@@ -0,0 +1,100 @@
1+\input texinfo @c -*-texinfo-*-
2+@c %**start of header
3+@setfilename parser.info
4+@settitle Python Parser Module Reference
5+@setchapternewpage odd
6+@footnotestyle end
7+@c %**end of header
8+
9+@ifinfo
10+This file describes the interfaces
11+published by the optional @code{parser} module and gives examples of
12+how they may be used. It contains the same text as the chapter on the
13+@code{parser} module in the @cite{Python Library Reference}, but is
14+presented as a separate document.
15+
16+Copyright 1995-1996 by Fred L. Drake, Jr., Reston, Virginia, USA, and
17+Virginia Polytechnic Institute and State University, Blacksburg,
18+Virginia, USA. Portions of the software copyright 1991-1995 by
19+Stichting Mathematisch Centrum, Amsterdam, The Netherlands. Copying is
20+permitted under the terms associated with the main Python distribution,
21+with the additional restriction that this additional notice be included
22+and maintained on all distributed copies.
23+
24+ All Rights Reserved
25+
26+Permission to use, copy, modify, and distribute this software and its
27+documentation for any purpose and without fee is hereby granted,
28+provided that the above copyright notice appear in all copies and that
29+both that copyright notice and this permission notice appear in
30+supporting documentation, and that the names of Fred L. Drake, Jr. and
31+Virginia Polytechnic Institute and State University not be used in
32+advertising or publicity pertaining to distribution of the software
33+without specific, written prior permission.
34+
35+FRED L. DRAKE, JR. AND VIRGINIA POLYTECHNIC INSTITUTE AND STATE
36+UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
37+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
38+EVENT SHALL FRED L. DRAKE, JR. OR VIRGINIA POLYTECHNIC INSTITUTE AND
39+STATE UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
40+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
41+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
42+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
43+PERFORMANCE OF THIS SOFTWARE.
44+@end ifinfo
45+
46+@titlepage
47+@title Python Parser Module Reference
48+@author Fred L. Drake, Jr.
49+
50+@c The following two commands start the copyright page.
51+@page
52+@vskip 0pt plus 1filll
53+Copyright 1995-1996 by Fred L. Drake, Jr., Reston, Virginia, USA, and
54+Virginia Polytechnic Institute and State University, Blacksburg,
55+Virginia, USA. Portions of the software copyright 1991-1995 by
56+Stichting Mathematisch Centrum, Amsterdam, The Netherlands. Copying is
57+permitted under the terms associated with the main Python distribution,
58+with the additional restriction that this additional notice be included
59+and maintained on all distributed copies.
60+
61+@center All Rights Reserved
62+
63+Permission to use, copy, modify, and distribute this software and its
64+documentation for any purpose and without fee is hereby granted,
65+provided that the above copyright notice appear in all copies and that
66+both that copyright notice and this permission notice appear in
67+supporting documentation, and that the names of Fred L. Drake, Jr. and
68+Virginia Polytechnic Institute and State University not be used in
69+advertising or publicity pertaining to distribution of the software
70+without specific, written prior permission.
71+
72+FRED L. DRAKE, JR. AND VIRGINIA POLYTECHNIC INSTITUTE AND STATE
73+UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
74+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
75+EVENT SHALL FRED L. DRAKE, JR. OR VIRGINIA POLYTECHNIC INSTITUTE AND
76+STATE UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
77+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
78+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
79+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
80+PERFORMANCE OF THIS SOFTWARE.
81+@end titlepage
82+
83+
84+@node Top, Overview, (dir), (dir)
85+@top The Python Parser Module
86+
87+@ifinfo
88+This file describes the interfaces
89+published by the optional @code{parser} module and gives examples of
90+how they may be used. It contains the same text as the chapter on the
91+@code{parser} module in the @cite{Python Library Reference}, but is
92+presented as a separate document.
93+
94+This version corresponds to Python version 1.4 (1 Sept. 1996).
95+
96+@end ifinfo
97+
98+@c placeholder for the master menu -- patched by texinfo-all-menus-update
99+@menu
100+@end menu
sys/src/cmd/python/Demo/parser/unparse.py+519−0
@@ -0,0 +1,519 @@
1+"Usage: unparse.py <path to source file>"
2+import sys
3+import _ast
4+import cStringIO
5+import os
6+
7+class Unparser:
8+ """Methods in this class recursively traverse an AST and
9+ output source code for the abstract syntax; original formatting
10+ is disregarged. """
11+
12+ def __init__(self, tree, file = sys.stdout):
13+ """Unparser(tree, file=sys.stdout) -> None.
14+ Print the source for tree to file."""
15+ self.f = file
16+ self._indent = 0
17+ self.dispatch(tree)
18+ print >>self.f,""
19+ self.f.flush()
20+
21+ def fill(self, text = ""):
22+ "Indent a piece of text, according to the current indentation level"
23+ self.f.write("\n"+" "*self._indent + text)
24+
25+ def write(self, text):
26+ "Append a piece of text to the current line."
27+ self.f.write(text)
28+
29+ def enter(self):
30+ "Print ':', and increase the indentation."
31+ self.write(":")
32+ self._indent += 1
33+
34+ def leave(self):
35+ "Decrease the indentation level."
36+ self._indent -= 1
37+
38+ def dispatch(self, tree):
39+ "Dispatcher function, dispatching tree type T to method _T."
40+ if isinstance(tree, list):
41+ for t in tree:
42+ self.dispatch(t)
43+ return
44+ meth = getattr(self, "_"+tree.__class__.__name__)
45+ meth(tree)
46+
47+
48+ ############### Unparsing methods ######################
49+ # There should be one method per concrete grammar type #
50+ # Constructors should be grouped by sum type. Ideally, #
51+ # this would follow the order in the grammar, but #
52+ # currently doesn't. #
53+ ########################################################
54+
55+ def _Module(self, tree):
56+ for stmt in tree.body:
57+ self.dispatch(stmt)
58+
59+ # stmt
60+ def _Expr(self, tree):
61+ self.fill()
62+ self.dispatch(tree.value)
63+
64+ def _Import(self, t):
65+ self.fill("import ")
66+ first = True
67+ for a in t.names:
68+ if first:
69+ first = False
70+ else:
71+ self.write(", ")
72+ self.write(a.name)
73+ if a.asname:
74+ self.write(" as "+a.asname)
75+
76+ def _ImportFrom(self, t):
77+ self.fill("from ")
78+ self.write(t.module)
79+ self.write(" import ")
80+ for i, a in enumerate(t.names):
81+ if i == 0:
82+ self.write(", ")
83+ self.write(a.name)
84+ if a.asname:
85+ self.write(" as "+a.asname)
86+ # XXX(jpe) what is level for?
87+
88+ def _Assign(self, t):
89+ self.fill()
90+ for target in t.targets:
91+ self.dispatch(target)
92+ self.write(" = ")
93+ self.dispatch(t.value)
94+
95+ def _AugAssign(self, t):
96+ self.fill()
97+ self.dispatch(t.target)
98+ self.write(" "+self.binop[t.op.__class__.__name__]+"= ")
99+ self.dispatch(t.value)
100+
101+ def _Return(self, t):
102+ self.fill("return ")
103+ if t.value:
104+ self.dispatch(t.value)
105+
106+ def _Pass(self, t):
107+ self.fill("pass")
108+
109+ def _Break(self, t):
110+ self.fill("break")
111+
112+ def _Continue(self, t):
113+ self.fill("continue")
114+
115+ def _Delete(self, t):
116+ self.fill("del ")
117+ self.dispatch(t.targets)
118+
119+ def _Assert(self, t):
120+ self.fill("assert ")
121+ self.dispatch(t.test)
122+ if t.msg:
123+ self.write(", ")
124+ self.dispatch(t.msg)
125+
126+ def _Exec(self, t):
127+ self.fill("exec ")
128+ self.dispatch(t.body)
129+ if t.globals:
130+ self.write(" in ")
131+ self.dispatch(t.globals)
132+ if t.locals:
133+ self.write(", ")
134+ self.dispatch(t.locals)
135+
136+ def _Print(self, t):
137+ self.fill("print ")
138+ do_comma = False
139+ if t.dest:
140+ self.write(">>")
141+ self.dispatch(t.dest)
142+ do_comma = True
143+ for e in t.values:
144+ if do_comma:self.write(", ")
145+ else:do_comma=True
146+ self.dispatch(e)
147+ if not t.nl:
148+ self.write(",")
149+
150+ def _Global(self, t):
151+ self.fill("global")
152+ for i, n in enumerate(t.names):
153+ if i != 0:
154+ self.write(",")
155+ self.write(" " + n)
156+
157+ def _Yield(self, t):
158+ self.fill("yield")
159+ if t.value:
160+ self.write(" (")
161+ self.dispatch(t.value)
162+ self.write(")")
163+
164+ def _Raise(self, t):
165+ self.fill('raise ')
166+ if t.type:
167+ self.dispatch(t.type)
168+ if t.inst:
169+ self.write(", ")
170+ self.dispatch(t.inst)
171+ if t.tback:
172+ self.write(", ")
173+ self.dispatch(t.tback)
174+
175+ def _TryExcept(self, t):
176+ self.fill("try")
177+ self.enter()
178+ self.dispatch(t.body)
179+ self.leave()
180+
181+ for ex in t.handlers:
182+ self.dispatch(ex)
183+ if t.orelse:
184+ self.fill("else")
185+ self.enter()
186+ self.dispatch(t.orelse)
187+ self.leave()
188+
189+ def _TryFinally(self, t):
190+ self.fill("try")
191+ self.enter()
192+ self.dispatch(t.body)
193+ self.leave()
194+
195+ self.fill("finally")
196+ self.enter()
197+ self.dispatch(t.finalbody)
198+ self.leave()
199+
200+ def _excepthandler(self, t):
201+ self.fill("except ")
202+ if t.type:
203+ self.dispatch(t.type)
204+ if t.name:
205+ self.write(", ")
206+ self.dispatch(t.name)
207+ self.enter()
208+ self.dispatch(t.body)
209+ self.leave()
210+
211+ def _ClassDef(self, t):
212+ self.write("\n")
213+ self.fill("class "+t.name)
214+ if t.bases:
215+ self.write("(")
216+ for a in t.bases:
217+ self.dispatch(a)
218+ self.write(", ")
219+ self.write(")")
220+ self.enter()
221+ self.dispatch(t.body)
222+ self.leave()
223+
224+ def _FunctionDef(self, t):
225+ self.write("\n")
226+ for deco in t.decorators:
227+ self.fill("@")
228+ self.dispatch(deco)
229+ self.fill("def "+t.name + "(")
230+ self.dispatch(t.args)
231+ self.write(")")
232+ self.enter()
233+ self.dispatch(t.body)
234+ self.leave()
235+
236+ def _For(self, t):
237+ self.fill("for ")
238+ self.dispatch(t.target)
239+ self.write(" in ")
240+ self.dispatch(t.iter)
241+ self.enter()
242+ self.dispatch(t.body)
243+ self.leave()
244+ if t.orelse:
245+ self.fill("else")
246+ self.enter()
247+ self.dispatch(t.orelse)
248+ self.leave
249+
250+ def _If(self, t):
251+ self.fill("if ")
252+ self.dispatch(t.test)
253+ self.enter()
254+ # XXX elif?
255+ self.dispatch(t.body)
256+ self.leave()
257+ if t.orelse:
258+ self.fill("else")
259+ self.enter()
260+ self.dispatch(t.orelse)
261+ self.leave()
262+
263+ def _While(self, t):
264+ self.fill("while ")
265+ self.dispatch(t.test)
266+ self.enter()
267+ self.dispatch(t.body)
268+ self.leave()
269+ if t.orelse:
270+ self.fill("else")
271+ self.enter()
272+ self.dispatch(t.orelse)
273+ self.leave
274+
275+ def _With(self, t):
276+ self.fill("with ")
277+ self.dispatch(t.context_expr)
278+ if t.optional_vars:
279+ self.write(" as ")
280+ self.dispatch(t.optional_vars)
281+ self.enter()
282+ self.dispatch(t.body)
283+ self.leave()
284+
285+ # expr
286+ def _Str(self, tree):
287+ self.write(repr(tree.s))
288+
289+ def _Name(self, t):
290+ self.write(t.id)
291+
292+ def _Repr(self, t):
293+ self.write("`")
294+ self.dispatch(t.value)
295+ self.write("`")
296+
297+ def _Num(self, t):
298+ self.write(repr(t.n))
299+
300+ def _List(self, t):
301+ self.write("[")
302+ for e in t.elts:
303+ self.dispatch(e)
304+ self.write(", ")
305+ self.write("]")
306+
307+ def _ListComp(self, t):
308+ self.write("[")
309+ self.dispatch(t.elt)
310+ for gen in t.generators:
311+ self.dispatch(gen)
312+ self.write("]")
313+
314+ def _GeneratorExp(self, t):
315+ self.write("(")
316+ self.dispatch(t.elt)
317+ for gen in t.generators:
318+ self.dispatch(gen)
319+ self.write(")")
320+
321+ def _comprehension(self, t):
322+ self.write(" for ")
323+ self.dispatch(t.target)
324+ self.write(" in ")
325+ self.dispatch(t.iter)
326+ for if_clause in t.ifs:
327+ self.write(" if ")
328+ self.dispatch(if_clause)
329+
330+ def _IfExp(self, t):
331+ self.dispatch(t.body)
332+ self.write(" if ")
333+ self.dispatch(t.test)
334+ if t.orelse:
335+ self.write(" else ")
336+ self.dispatch(t.orelse)
337+
338+ def _Dict(self, t):
339+ self.write("{")
340+ for k,v in zip(t.keys, t.values):
341+ self.dispatch(k)
342+ self.write(" : ")
343+ self.dispatch(v)
344+ self.write(", ")
345+ self.write("}")
346+
347+ def _Tuple(self, t):
348+ if not t.elts:
349+ self.write("()")
350+ return
351+ self.write("(")
352+ for e in t.elts:
353+ self.dispatch(e)
354+ self.write(", ")
355+ self.write(")")
356+
357+ unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
358+ def _UnaryOp(self, t):
359+ self.write(self.unop[t.op.__class__.__name__])
360+ self.write("(")
361+ self.dispatch(t.operand)
362+ self.write(")")
363+
364+ binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
365+ "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
366+ "FloorDiv":"//", "Pow": "**"}
367+ def _BinOp(self, t):
368+ self.write("(")
369+ self.dispatch(t.left)
370+ self.write(")" + self.binop[t.op.__class__.__name__] + "(")
371+ self.dispatch(t.right)
372+ self.write(")")
373+
374+ cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
375+ "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
376+ def _Compare(self, t):
377+ self.write("(")
378+ self.dispatch(t.left)
379+ for o, e in zip(t.ops, t.comparators):
380+ self.write(") " +self.cmpops[o.__class__.__name__] + " (")
381+ self.dispatch(e)
382+ self.write(")")
383+
384+ boolops = {_ast.And: 'and', _ast.Or: 'or'}
385+ def _BoolOp(self, t):
386+ self.write("(")
387+ self.dispatch(t.values[0])
388+ for v in t.values[1:]:
389+ self.write(" %s " % self.boolops[t.op.__class__])
390+ self.dispatch(v)
391+ self.write(")")
392+
393+ def _Attribute(self,t):
394+ self.dispatch(t.value)
395+ self.write(".")
396+ self.write(t.attr)
397+
398+ def _Call(self, t):
399+ self.dispatch(t.func)
400+ self.write("(")
401+ comma = False
402+ for e in t.args:
403+ if comma: self.write(", ")
404+ else: comma = True
405+ self.dispatch(e)
406+ for e in t.keywords:
407+ if comma: self.write(", ")
408+ else: comma = True
409+ self.dispatch(e)
410+ if t.starargs:
411+ if comma: self.write(", ")
412+ else: comma = True
413+ self.write("*")
414+ self.dispatch(t.starargs)
415+ if t.kwargs:
416+ if comma: self.write(", ")
417+ else: comma = True
418+ self.write("**")
419+ self.dispatch(t.kwargs)
420+ self.write(")")
421+
422+ def _Subscript(self, t):
423+ self.dispatch(t.value)
424+ self.write("[")
425+ self.dispatch(t.slice)
426+ self.write("]")
427+
428+ # slice
429+ def _Ellipsis(self, t):
430+ self.write("...")
431+
432+ def _Index(self, t):
433+ self.dispatch(t.value)
434+
435+ def _Slice(self, t):
436+ if t.lower:
437+ self.dispatch(t.lower)
438+ self.write(":")
439+ if t.upper:
440+ self.dispatch(t.upper)
441+ if t.step:
442+ self.write(":")
443+ self.dispatch(t.step)
444+
445+ def _ExtSlice(self, t):
446+ for i, d in enumerate(t.dims):
447+ if i != 0:
448+ self.write(': ')
449+ self.dispatch(d)
450+
451+ # others
452+ def _arguments(self, t):
453+ first = True
454+ nonDef = len(t.args)-len(t.defaults)
455+ for a in t.args[0:nonDef]:
456+ if first:first = False
457+ else: self.write(", ")
458+ self.dispatch(a)
459+ for a,d in zip(t.args[nonDef:], t.defaults):
460+ if first:first = False
461+ else: self.write(", ")
462+ self.dispatch(a),
463+ self.write("=")
464+ self.dispatch(d)
465+ if t.vararg:
466+ if first:first = False
467+ else: self.write(", ")
468+ self.write("*"+t.vararg)
469+ if t.kwarg:
470+ if first:first = False
471+ else: self.write(", ")
472+ self.write("**"+t.kwarg)
473+
474+ def _keyword(self, t):
475+ self.write(t.arg)
476+ self.write("=")
477+ self.dispatch(t.value)
478+
479+ def _Lambda(self, t):
480+ self.write("lambda ")
481+ self.dispatch(t.args)
482+ self.write(": ")
483+ self.dispatch(t.body)
484+
485+def roundtrip(filename, output=sys.stdout):
486+ source = open(filename).read()
487+ tree = compile(source, filename, "exec", 0x400)
488+ Unparser(tree, output)
489+
490+
491+
492+def testdir(a):
493+ try:
494+ names = [n for n in os.listdir(a) if n.endswith('.py')]
495+ except OSError:
496+ print >> sys.stderr, "Directory not readable: %s" % a
497+ else:
498+ for n in names:
499+ fullname = os.path.join(a, n)
500+ if os.path.isfile(fullname):
501+ output = cStringIO.StringIO()
502+ print 'Testing %s' % fullname
503+ try:
504+ roundtrip(fullname, output)
505+ except Exception, e:
506+ print ' Failed to compile, exception is %s' % repr(e)
507+ elif os.path.isdir(fullname):
508+ testdir(fullname)
509+
510+def main(args):
511+ if args[0] == '--testdir':
512+ for a in args[1:]:
513+ testdir(a)
514+ else:
515+ for a in args:
516+ roundtrip(a)
517+
518+if __name__=='__main__':
519+ main(sys.argv[1:])
sys/src/cmd/python/Demo/pdist/FSProxy.py+322−0
@@ -0,0 +1,322 @@
1+"""File System Proxy.
2+
3+Provide an OS-neutral view on a file system, locally or remotely.
4+The functionality is geared towards implementing some sort of
5+rdist-like utility between a Mac and a UNIX system.
6+
7+The module defines three classes:
8+
9+FSProxyLocal -- used for local access
10+FSProxyServer -- used on the server side of remote access
11+FSProxyClient -- used on the client side of remote access
12+
13+The remote classes are instantiated with an IP address and an optional
14+verbosity flag.
15+"""
16+
17+import server
18+import client
19+import md5
20+import os
21+import fnmatch
22+from stat import *
23+import time
24+import fnmatch
25+
26+if os.name == 'mac':
27+ import macfs
28+ maxnamelen = 31
29+else:
30+ macfs = None
31+ maxnamelen = 255
32+
33+skipnames = (os.curdir, os.pardir)
34+
35+
36+class FSProxyLocal:
37+
38+ def __init__(self):
39+ self._dirstack = []
40+ self._ignore = ['*.pyc'] + self._readignore()
41+
42+ def _close(self):
43+ while self._dirstack:
44+ self.back()
45+
46+ def _readignore(self):
47+ file = self._hide('ignore')
48+ try:
49+ f = open(file)
50+ except IOError:
51+ file = self._hide('synctree.ignorefiles')
52+ try:
53+ f = open(file)
54+ except IOError:
55+ return []
56+ ignore = []
57+ while 1:
58+ line = f.readline()
59+ if not line: break
60+ if line[-1] == '\n': line = line[:-1]
61+ ignore.append(line)
62+ f.close()
63+ return ignore
64+
65+ def _hidden(self, name):
66+ if os.name == 'mac':
67+ return name[0] == '(' and name[-1] == ')'
68+ else:
69+ return name[0] == '.'
70+
71+ def _hide(self, name):
72+ if os.name == 'mac':
73+ return '(%s)' % name
74+ else:
75+ return '.%s' % name
76+
77+ def visible(self, name):
78+ if len(name) > maxnamelen: return 0
79+ if name[-1] == '~': return 0
80+ if name in skipnames: return 0
81+ if self._hidden(name): return 0
82+ head, tail = os.path.split(name)
83+ if head or not tail: return 0
84+ if macfs:
85+ if os.path.exists(name) and not os.path.isdir(name):
86+ try:
87+ fs = macfs.FSSpec(name)
88+ c, t = fs.GetCreatorType()
89+ if t != 'TEXT': return 0
90+ except macfs.error, msg:
91+ print "***", name, msg
92+ return 0
93+ else:
94+ if os.path.islink(name): return 0
95+ if '\0' in open(name, 'rb').read(512): return 0
96+ for ign in self._ignore:
97+ if fnmatch.fnmatch(name, ign): return 0
98+ return 1
99+
100+ def check(self, name):
101+ if not self.visible(name):
102+ raise os.error, "protected name %s" % repr(name)
103+
104+ def checkfile(self, name):
105+ self.check(name)
106+ if not os.path.isfile(name):
107+ raise os.error, "not a plain file %s" % repr(name)
108+
109+ def pwd(self):
110+ return os.getcwd()
111+
112+ def cd(self, name):
113+ self.check(name)
114+ save = os.getcwd(), self._ignore
115+ os.chdir(name)
116+ self._dirstack.append(save)
117+ self._ignore = self._ignore + self._readignore()
118+
119+ def back(self):
120+ if not self._dirstack:
121+ raise os.error, "empty directory stack"
122+ dir, ignore = self._dirstack[-1]
123+ os.chdir(dir)
124+ del self._dirstack[-1]
125+ self._ignore = ignore
126+
127+ def _filter(self, files, pat = None):
128+ if pat:
129+ def keep(name, pat = pat):
130+ return fnmatch.fnmatch(name, pat)
131+ files = filter(keep, files)
132+ files = filter(self.visible, files)
133+ files.sort()
134+ return files
135+
136+ def list(self, pat = None):
137+ files = os.listdir(os.curdir)
138+ return self._filter(files, pat)
139+
140+ def listfiles(self, pat = None):
141+ files = os.listdir(os.curdir)
142+ files = filter(os.path.isfile, files)
143+ return self._filter(files, pat)
144+
145+ def listsubdirs(self, pat = None):
146+ files = os.listdir(os.curdir)
147+ files = filter(os.path.isdir, files)
148+ return self._filter(files, pat)
149+
150+ def exists(self, name):
151+ return self.visible(name) and os.path.exists(name)
152+
153+ def isdir(self, name):
154+ return self.visible(name) and os.path.isdir(name)
155+
156+ def islink(self, name):
157+ return self.visible(name) and os.path.islink(name)
158+
159+ def isfile(self, name):
160+ return self.visible(name) and os.path.isfile(name)
161+
162+ def sum(self, name):
163+ self.checkfile(name)
164+ BUFFERSIZE = 1024*8
165+ f = open(name)
166+ sum = md5.new()
167+ while 1:
168+ buffer = f.read(BUFFERSIZE)
169+ if not buffer:
170+ break
171+ sum.update(buffer)
172+ return sum.digest()
173+
174+ def size(self, name):
175+ self.checkfile(name)
176+ return os.stat(name)[ST_SIZE]
177+
178+ def mtime(self, name):
179+ self.checkfile(name)
180+ return time.localtime(os.stat(name)[ST_MTIME])
181+
182+ def stat(self, name):
183+ self.checkfile(name)
184+ size = os.stat(name)[ST_SIZE]
185+ mtime = time.localtime(os.stat(name)[ST_MTIME])
186+ return size, mtime
187+
188+ def info(self, name):
189+ sum = self.sum(name)
190+ size = os.stat(name)[ST_SIZE]
191+ mtime = time.localtime(os.stat(name)[ST_MTIME])
192+ return sum, size, mtime
193+
194+ def _list(self, function, list):
195+ if list is None:
196+ list = self.listfiles()
197+ res = []
198+ for name in list:
199+ try:
200+ res.append((name, function(name)))
201+ except (os.error, IOError):
202+ res.append((name, None))
203+ return res
204+
205+ def sumlist(self, list = None):
206+ return self._list(self.sum, list)
207+
208+ def statlist(self, list = None):
209+ return self._list(self.stat, list)
210+
211+ def mtimelist(self, list = None):
212+ return self._list(self.mtime, list)
213+
214+ def sizelist(self, list = None):
215+ return self._list(self.size, list)
216+
217+ def infolist(self, list = None):
218+ return self._list(self.info, list)
219+
220+ def _dict(self, function, list):
221+ if list is None:
222+ list = self.listfiles()
223+ dict = {}
224+ for name in list:
225+ try:
226+ dict[name] = function(name)
227+ except (os.error, IOError):
228+ pass
229+ return dict
230+
231+ def sumdict(self, list = None):
232+ return self.dict(self.sum, list)
233+
234+ def sizedict(self, list = None):
235+ return self.dict(self.size, list)
236+
237+ def mtimedict(self, list = None):
238+ return self.dict(self.mtime, list)
239+
240+ def statdict(self, list = None):
241+ return self.dict(self.stat, list)
242+
243+ def infodict(self, list = None):
244+ return self._dict(self.info, list)
245+
246+ def read(self, name, offset = 0, length = -1):
247+ self.checkfile(name)
248+ f = open(name)
249+ f.seek(offset)
250+ if length == 0:
251+ data = ''
252+ elif length < 0:
253+ data = f.read()
254+ else:
255+ data = f.read(length)
256+ f.close()
257+ return data
258+
259+ def create(self, name):
260+ self.check(name)
261+ if os.path.exists(name):
262+ self.checkfile(name)
263+ bname = name + '~'
264+ try:
265+ os.unlink(bname)
266+ except os.error:
267+ pass
268+ os.rename(name, bname)
269+ f = open(name, 'w')
270+ f.close()
271+
272+ def write(self, name, data, offset = 0):
273+ self.checkfile(name)
274+ f = open(name, 'r+')
275+ f.seek(offset)
276+ f.write(data)
277+ f.close()
278+
279+ def mkdir(self, name):
280+ self.check(name)
281+ os.mkdir(name, 0777)
282+
283+ def rmdir(self, name):
284+ self.check(name)
285+ os.rmdir(name)
286+
287+
288+class FSProxyServer(FSProxyLocal, server.Server):
289+
290+ def __init__(self, address, verbose = server.VERBOSE):
291+ FSProxyLocal.__init__(self)
292+ server.Server.__init__(self, address, verbose)
293+
294+ def _close(self):
295+ server.Server._close(self)
296+ FSProxyLocal._close(self)
297+
298+ def _serve(self):
299+ server.Server._serve(self)
300+ # Retreat into start directory
301+ while self._dirstack: self.back()
302+
303+
304+class FSProxyClient(client.Client):
305+
306+ def __init__(self, address, verbose = client.VERBOSE):
307+ client.Client.__init__(self, address, verbose)
308+
309+
310+def test():
311+ import string
312+ import sys
313+ if sys.argv[1:]:
314+ port = string.atoi(sys.argv[1])
315+ else:
316+ port = 4127
317+ proxy = FSProxyServer(('', port))
318+ proxy._serverloop()
319+
320+
321+if __name__ == '__main__':
322+ test()
sys/src/cmd/python/Demo/pdist/RCSProxy.py+198−0
@@ -0,0 +1,198 @@
1+#! /usr/bin/env python
2+
3+"""RCS Proxy.
4+
5+Provide a simplified interface on RCS files, locally or remotely.
6+The functionality is geared towards implementing some sort of
7+remote CVS like utility. It is modeled after the similar module
8+FSProxy.
9+
10+The module defines two classes:
11+
12+RCSProxyLocal -- used for local access
13+RCSProxyServer -- used on the server side of remote access
14+
15+The corresponding client class, RCSProxyClient, is defined in module
16+rcsclient.
17+
18+The remote classes are instantiated with an IP address and an optional
19+verbosity flag.
20+"""
21+
22+import server
23+import md5
24+import os
25+import fnmatch
26+import string
27+import tempfile
28+import rcslib
29+
30+
31+class DirSupport:
32+
33+ def __init__(self):
34+ self._dirstack = []
35+
36+ def __del__(self):
37+ self._close()
38+
39+ def _close(self):
40+ while self._dirstack:
41+ self.back()
42+
43+ def pwd(self):
44+ return os.getcwd()
45+
46+ def cd(self, name):
47+ save = os.getcwd()
48+ os.chdir(name)
49+ self._dirstack.append(save)
50+
51+ def back(self):
52+ if not self._dirstack:
53+ raise os.error, "empty directory stack"
54+ dir = self._dirstack[-1]
55+ os.chdir(dir)
56+ del self._dirstack[-1]
57+
58+ def listsubdirs(self, pat = None):
59+ files = os.listdir(os.curdir)
60+ files = filter(os.path.isdir, files)
61+ return self._filter(files, pat)
62+
63+ def isdir(self, name):
64+ return os.path.isdir(name)
65+
66+ def mkdir(self, name):
67+ os.mkdir(name, 0777)
68+
69+ def rmdir(self, name):
70+ os.rmdir(name)
71+
72+
73+class RCSProxyLocal(rcslib.RCS, DirSupport):
74+
75+ def __init__(self):
76+ rcslib.RCS.__init__(self)
77+ DirSupport.__init__(self)
78+
79+ def __del__(self):
80+ DirSupport.__del__(self)
81+ rcslib.RCS.__del__(self)
82+
83+ def sumlist(self, list = None):
84+ return self._list(self.sum, list)
85+
86+ def sumdict(self, list = None):
87+ return self._dict(self.sum, list)
88+
89+ def sum(self, name_rev):
90+ f = self._open(name_rev)
91+ BUFFERSIZE = 1024*8
92+ sum = md5.new()
93+ while 1:
94+ buffer = f.read(BUFFERSIZE)
95+ if not buffer:
96+ break
97+ sum.update(buffer)
98+ self._closepipe(f)
99+ return sum.digest()
100+
101+ def get(self, name_rev):
102+ f = self._open(name_rev)
103+ data = f.read()
104+ self._closepipe(f)
105+ return data
106+
107+ def put(self, name_rev, data, message=None):
108+ name, rev = self._unmangle(name_rev)
109+ f = open(name, 'w')
110+ f.write(data)
111+ f.close()
112+ self.checkin(name_rev, message)
113+ self._remove(name)
114+
115+ def _list(self, function, list = None):
116+ """INTERNAL: apply FUNCTION to all files in LIST.
117+
118+ Return a list of the results.
119+
120+ The list defaults to all files in the directory if None.
121+
122+ """
123+ if list is None:
124+ list = self.listfiles()
125+ res = []
126+ for name in list:
127+ try:
128+ res.append((name, function(name)))
129+ except (os.error, IOError):
130+ res.append((name, None))
131+ return res
132+
133+ def _dict(self, function, list = None):
134+ """INTERNAL: apply FUNCTION to all files in LIST.
135+
136+ Return a dictionary mapping files to results.
137+
138+ The list defaults to all files in the directory if None.
139+
140+ """
141+ if list is None:
142+ list = self.listfiles()
143+ dict = {}
144+ for name in list:
145+ try:
146+ dict[name] = function(name)
147+ except (os.error, IOError):
148+ pass
149+ return dict
150+
151+
152+class RCSProxyServer(RCSProxyLocal, server.SecureServer):
153+
154+ def __init__(self, address, verbose = server.VERBOSE):
155+ RCSProxyLocal.__init__(self)
156+ server.SecureServer.__init__(self, address, verbose)
157+
158+ def _close(self):
159+ server.SecureServer._close(self)
160+ RCSProxyLocal._close(self)
161+
162+ def _serve(self):
163+ server.SecureServer._serve(self)
164+ # Retreat into start directory
165+ while self._dirstack: self.back()
166+
167+
168+def test_server():
169+ import string
170+ import sys
171+ if sys.argv[1:]:
172+ port = string.atoi(sys.argv[1])
173+ else:
174+ port = 4127
175+ proxy = RCSProxyServer(('', port))
176+ proxy._serverloop()
177+
178+
179+def test():
180+ import sys
181+ if not sys.argv[1:] or sys.argv[1] and sys.argv[1][0] in '0123456789':
182+ test_server()
183+ sys.exit(0)
184+ proxy = RCSProxyLocal()
185+ what = sys.argv[1]
186+ if hasattr(proxy, what):
187+ attr = getattr(proxy, what)
188+ if callable(attr):
189+ print apply(attr, tuple(sys.argv[2:]))
190+ else:
191+ print repr(attr)
192+ else:
193+ print "%s: no such attribute" % what
194+ sys.exit(2)
195+
196+
197+if __name__ == '__main__':
198+ test()
sys/src/cmd/python/Demo/pdist/README+121−0
@@ -0,0 +1,121 @@
1+Filesystem, RCS and CVS client and server classes
2+=================================================
3+
4+*** See the security warning at the end of this file! ***
5+
6+This directory contains various modules and classes that support
7+remote file system operations.
8+
9+CVS stuff
10+---------
11+
12+rcvs Script to put in your bin directory
13+rcvs.py Remote CVS client command line interface
14+
15+cvslib.py CVS admin files classes (used by rrcs)
16+cvslock.py CVS locking algorithms
17+
18+RCS stuff
19+---------
20+
21+rrcs Script to put in your bin directory
22+rrcs.py Remote RCS client command line interface
23+
24+rcsclient.py Return an RCSProxyClient instance
25+ (has reasonable default server/port/directory)
26+
27+RCSProxy.py RCS proxy and server classes (on top of rcslib.py)
28+
29+rcslib.py Local-only RCS base class (affects stdout &
30+ local work files)
31+
32+FSProxy stuff
33+-------------
34+
35+sumtree.py Old demo for FSProxy
36+cmptree.py First FSProxy client (used to sync from the Mac)
37+FSProxy.py Filesystem interface classes
38+
39+Generic client/server stuff
40+---------------------------
41+
42+client.py Client class
43+server.py Server class
44+
45+security.py Security mix-in class (not very secure I think)
46+
47+Other generic stuff
48+-------------------
49+
50+cmdfw.py CommandFrameWork class
51+ (used by rcvs, should be used by rrcs as well)
52+
53+
54+Client/Server operation
55+-----------------------
56+
57+The Client and Server classes implement a simple-minded RPC protocol,
58+using Python's pickle module to transfer arguments, return values and
59+exceptions with the most generality. The Server class is instantiated
60+with a port number on which it should listen for requests; the Client
61+class is instantiated with a host name and a port number where it
62+should connect to. Once a client is connected, a TCP connection is
63+maintained between client and server.
64+
65+The Server class currently handles only one connection at a time;
66+however it could be rewritten to allow various modes of operations,
67+using multiple threads or processes or the select() system call as
68+desired to serve multiple clients simultaneously (when using select(),
69+still handling one request at a time). This would not require
70+rewriting of the Client class. It may also be possible to adapt the
71+code to use UDP instead of TCP, but then both classes will have to be
72+rewritten (and unless extensive acknowlegements and request serial
73+numbers are used, the server should handle duplicate requests, so its
74+semantics should be idempotent -- shrudder).
75+
76+Even though the FSProxy and RCSProxy modules define client classes,
77+the client class is fully generic -- what methods it supports is
78+determined entirely by the server. The server class, however, must be
79+derived from. This is generally done as follows:
80+
81+ from server import Server
82+ from client import Client
83+
84+ # Define a class that performs the operations locally
85+ class MyClassLocal:
86+ def __init__(self): ...
87+ def _close(self): ...
88+
89+ # Derive a server class using multiple inheritance
90+ class MyClassServer(MyClassLocal, Server):
91+ def __init__(self, address):
92+ # Must initialize MyClassLocal as well as Server
93+ MyClassLocal.__init__(self)
94+ Server.__init__(self, address)
95+ def _close(self):
96+ Server._close()
97+ MyClassLocal._close()
98+
99+ # A dummy client class
100+ class MyClassClient(Client): pass
101+
102+Note that because MyClassLocal isn't used in the definition of
103+MyClassClient, it would actually be better to place it in a separate
104+module so the definition of MyClassLocal isn't executed when we only
105+instantiate a client.
106+
107+The modules client and server should probably be renamed to Client and
108+Server in order to match the class names.
109+
110+
111+*** Security warning: this version requires that you have a file
112+$HOME/.python_keyfile at the server and client side containing two
113+comma- separated numbers. The security system at the moment makes no
114+guarantees of actuallng being secure -- however it requires that the
115+key file exists and contains the same numbers at both ends for this to
116+work. (You can specify an alternative keyfile in $PYTHON_KEYFILE).
117+Have a look at the Security class in security.py for details;
118+basically, if the key file contains (x, y), then the security server
119+class chooses a random number z (the challenge) in the range
120+10..100000 and the client must be able to produce pow(z, x, y)
121+(i.e. z**x mod y).
sys/src/cmd/python/Demo/pdist/client.py+157−0
@@ -0,0 +1,157 @@
1+"""RPC Client module."""
2+
3+import sys
4+import socket
5+import pickle
6+import __builtin__
7+import os
8+
9+
10+# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)
11+VERBOSE = 1
12+
13+
14+class Client:
15+
16+ """RPC Client class. No need to derive a class -- it's fully generic."""
17+
18+ def __init__(self, address, verbose = VERBOSE):
19+ self._pre_init(address, verbose)
20+ self._post_init()
21+
22+ def _pre_init(self, address, verbose = VERBOSE):
23+ if type(address) == type(0):
24+ address = ('', address)
25+ self._address = address
26+ self._verbose = verbose
27+ if self._verbose: print "Connecting to %s ..." % repr(address)
28+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
29+ self._socket.connect(address)
30+ if self._verbose: print "Connected."
31+ self._lastid = 0 # Last id for which a reply has been received
32+ self._nextid = 1 # Id of next request
33+ self._replies = {} # Unprocessed replies
34+ self._rf = self._socket.makefile('r')
35+ self._wf = self._socket.makefile('w')
36+
37+ def _post_init(self):
38+ self._methods = self._call('.methods')
39+
40+ def __del__(self):
41+ self._close()
42+
43+ def _close(self):
44+ if self._rf: self._rf.close()
45+ self._rf = None
46+ if self._wf: self._wf.close()
47+ self._wf = None
48+ if self._socket: self._socket.close()
49+ self._socket = None
50+
51+ def __getattr__(self, name):
52+ if name in self._methods:
53+ method = _stub(self, name)
54+ setattr(self, name, method) # XXX circular reference
55+ return method
56+ raise AttributeError, name
57+
58+ def _setverbose(self, verbose):
59+ self._verbose = verbose
60+
61+ def _call(self, name, *args):
62+ return self._vcall(name, args)
63+
64+ def _vcall(self, name, args):
65+ return self._recv(self._vsend(name, args))
66+
67+ def _send(self, name, *args):
68+ return self._vsend(name, args)
69+
70+ def _send_noreply(self, name, *args):
71+ return self._vsend(name, args, 0)
72+
73+ def _vsend_noreply(self, name, args):
74+ return self._vsend(name, args, 0)
75+
76+ def _vsend(self, name, args, wantreply = 1):
77+ id = self._nextid
78+ self._nextid = id+1
79+ if not wantreply: id = -id
80+ request = (name, args, id)
81+ if self._verbose > 1: print "sending request: %s" % repr(request)
82+ wp = pickle.Pickler(self._wf)
83+ wp.dump(request)
84+ return id
85+
86+ def _recv(self, id):
87+ exception, value, rid = self._vrecv(id)
88+ if rid != id:
89+ raise RuntimeError, "request/reply id mismatch: %d/%d" % (id, rid)
90+ if exception is None:
91+ return value
92+ x = exception
93+ if hasattr(__builtin__, exception):
94+ x = getattr(__builtin__, exception)
95+ elif exception in ('posix.error', 'mac.error'):
96+ x = os.error
97+ if x == exception:
98+ exception = x
99+ raise exception, value
100+
101+ def _vrecv(self, id):
102+ self._flush()
103+ if self._replies.has_key(id):
104+ if self._verbose > 1: print "retrieving previous reply, id = %d" % id
105+ reply = self._replies[id]
106+ del self._replies[id]
107+ return reply
108+ aid = abs(id)
109+ while 1:
110+ if self._verbose > 1: print "waiting for reply, id = %d" % id
111+ rp = pickle.Unpickler(self._rf)
112+ reply = rp.load()
113+ del rp
114+ if self._verbose > 1: print "got reply: %s" % repr(reply)
115+ rid = reply[2]
116+ arid = abs(rid)
117+ if arid == aid:
118+ if self._verbose > 1: print "got it"
119+ return reply
120+ self._replies[rid] = reply
121+ if arid > aid:
122+ if self._verbose > 1: print "got higher id, assume all ok"
123+ return (None, None, id)
124+
125+ def _flush(self):
126+ self._wf.flush()
127+
128+
129+from security import Security
130+
131+
132+class SecureClient(Client, Security):
133+
134+ def __init__(self, *args):
135+ import string
136+ apply(self._pre_init, args)
137+ Security.__init__(self)
138+ self._wf.flush()
139+ line = self._rf.readline()
140+ challenge = string.atoi(string.strip(line))
141+ response = self._encode_challenge(challenge)
142+ line = repr(long(response))
143+ if line[-1] in 'Ll': line = line[:-1]
144+ self._wf.write(line + '\n')
145+ self._wf.flush()
146+ self._post_init()
147+
148+class _stub:
149+
150+ """Helper class for Client -- each instance serves as a method of the client."""
151+
152+ def __init__(self, client, name):
153+ self._client = client
154+ self._name = name
155+
156+ def __call__(self, *args):
157+ return self._client._vcall(self._name, args)
sys/src/cmd/python/Demo/pdist/cmdfw.py+144−0
@@ -0,0 +1,144 @@
1+"Framework for command line interfaces like CVS. See class CmdFrameWork."
2+
3+
4+class CommandFrameWork:
5+
6+ """Framework class for command line interfaces like CVS.
7+
8+ The general command line structure is
9+
10+ command [flags] subcommand [subflags] [argument] ...
11+
12+ There's a class variable GlobalFlags which specifies the
13+ global flags options. Subcommands are defined by defining
14+ methods named do_<subcommand>. Flags for the subcommand are
15+ defined by defining class or instance variables named
16+ flags_<subcommand>. If there's no command, method default()
17+ is called. The __doc__ strings for the do_ methods are used
18+ for the usage message, printed after the general usage message
19+ which is the class variable UsageMessage. The class variable
20+ PostUsageMessage is printed after all the do_ methods' __doc__
21+ strings. The method's return value can be a suggested exit
22+ status. [XXX Need to rewrite this to clarify it.]
23+
24+ Common usage is to derive a class, instantiate it, and then call its
25+ run() method; by default this takes its arguments from sys.argv[1:].
26+ """
27+
28+ UsageMessage = \
29+ "usage: (name)s [flags] subcommand [subflags] [argument] ..."
30+
31+ PostUsageMessage = None
32+
33+ GlobalFlags = ''
34+
35+ def __init__(self):
36+ """Constructor, present for completeness."""
37+ pass
38+
39+ def run(self, args = None):
40+ """Process flags, subcommand and options, then run it."""
41+ import getopt, sys
42+ if args is None: args = sys.argv[1:]
43+ try:
44+ opts, args = getopt.getopt(args, self.GlobalFlags)
45+ except getopt.error, msg:
46+ return self.usage(msg)
47+ self.options(opts)
48+ if not args:
49+ self.ready()
50+ return self.default()
51+ else:
52+ cmd = args[0]
53+ mname = 'do_' + cmd
54+ fname = 'flags_' + cmd
55+ try:
56+ method = getattr(self, mname)
57+ except AttributeError:
58+ return self.usage("command %r unknown" % (cmd,))
59+ try:
60+ flags = getattr(self, fname)
61+ except AttributeError:
62+ flags = ''
63+ try:
64+ opts, args = getopt.getopt(args[1:], flags)
65+ except getopt.error, msg:
66+ return self.usage(
67+ "subcommand %s: " % cmd + str(msg))
68+ self.ready()
69+ return method(opts, args)
70+
71+ def options(self, opts):
72+ """Process the options retrieved by getopt.
73+ Override this if you have any options."""
74+ if opts:
75+ print "-"*40
76+ print "Options:"
77+ for o, a in opts:
78+ print 'option', o, 'value', repr(a)
79+ print "-"*40
80+
81+ def ready(self):
82+ """Called just before calling the subcommand."""
83+ pass
84+
85+ def usage(self, msg = None):
86+ """Print usage message. Return suitable exit code (2)."""
87+ if msg: print msg
88+ print self.UsageMessage % {'name': self.__class__.__name__}
89+ docstrings = {}
90+ c = self.__class__
91+ while 1:
92+ for name in dir(c):
93+ if name[:3] == 'do_':
94+ if docstrings.has_key(name):
95+ continue
96+ try:
97+ doc = getattr(c, name).__doc__
98+ except:
99+ doc = None
100+ if doc:
101+ docstrings[name] = doc
102+ if not c.__bases__:
103+ break
104+ c = c.__bases__[0]
105+ if docstrings:
106+ print "where subcommand can be:"
107+ names = docstrings.keys()
108+ names.sort()
109+ for name in names:
110+ print docstrings[name]
111+ if self.PostUsageMessage:
112+ print self.PostUsageMessage
113+ return 2
114+
115+ def default(self):
116+ """Default method, called when no subcommand is given.
117+ You should always override this."""
118+ print "Nobody expects the Spanish Inquisition!"
119+
120+
121+def test():
122+ """Test script -- called when this module is run as a script."""
123+ import sys
124+ class Hello(CommandFrameWork):
125+ def do_hello(self, opts, args):
126+ "hello -- print 'hello world', needs no arguments"
127+ print "Hello, world"
128+ x = Hello()
129+ tests = [
130+ [],
131+ ['hello'],
132+ ['spam'],
133+ ['-x'],
134+ ['hello', '-x'],
135+ None,
136+ ]
137+ for t in tests:
138+ print '-'*10, t, '-'*10
139+ sts = x.run(t)
140+ print "Exit status:", repr(sts)
141+
142+
143+if __name__ == '__main__':
144+ test()
sys/src/cmd/python/Demo/pdist/cmptree.py+208−0
@@ -0,0 +1,208 @@
1+"""Compare local and remote dictionaries and transfer differing files -- like rdist."""
2+
3+import sys
4+from repr import repr
5+import FSProxy
6+import time
7+import os
8+
9+def main():
10+ pwd = os.getcwd()
11+ s = raw_input("chdir [%s] " % pwd)
12+ if s:
13+ os.chdir(s)
14+ pwd = os.getcwd()
15+ host = ask("host", 'voorn.cwi.nl')
16+ port = 4127
17+ verbose = 1
18+ mode = ''
19+ print """\
20+Mode should be a string of characters, indicating what to do with differences.
21+r - read different files to local file system
22+w - write different files to remote file system
23+c - create new files, either remote or local
24+d - delete disappearing files, either remote or local
25+"""
26+ s = raw_input("mode [%s] " % mode)
27+ if s: mode = s
28+ address = (host, port)
29+ t1 = time.time()
30+ local = FSProxy.FSProxyLocal()
31+ remote = FSProxy.FSProxyClient(address, verbose)
32+ compare(local, remote, mode)
33+ remote._close()
34+ local._close()
35+ t2 = time.time()
36+ dt = t2-t1
37+ mins, secs = divmod(dt, 60)
38+ print mins, "minutes and", round(secs), "seconds"
39+ raw_input("[Return to exit] ")
40+
41+def ask(prompt, default):
42+ s = raw_input("%s [%s] " % (prompt, default))
43+ return s or default
44+
45+def askint(prompt, default):
46+ s = raw_input("%s [%s] " % (prompt, str(default)))
47+ if s: return string.atoi(s)
48+ return default
49+
50+def compare(local, remote, mode):
51+ print
52+ print "PWD =", repr(os.getcwd())
53+ sums_id = remote._send('sumlist')
54+ subdirs_id = remote._send('listsubdirs')
55+ remote._flush()
56+ print "calculating local sums ..."
57+ lsumdict = {}
58+ for name, info in local.sumlist():
59+ lsumdict[name] = info
60+ print "getting remote sums ..."
61+ sums = remote._recv(sums_id)
62+ print "got", len(sums)
63+ rsumdict = {}
64+ for name, rsum in sums:
65+ rsumdict[name] = rsum
66+ if not lsumdict.has_key(name):
67+ print repr(name), "only remote"
68+ if 'r' in mode and 'c' in mode:
69+ recvfile(local, remote, name)
70+ else:
71+ lsum = lsumdict[name]
72+ if lsum != rsum:
73+ print repr(name),
74+ rmtime = remote.mtime(name)
75+ lmtime = local.mtime(name)
76+ if rmtime > lmtime:
77+ print "remote newer",
78+ if 'r' in mode:
79+ recvfile(local, remote, name)
80+ elif lmtime > rmtime:
81+ print "local newer",
82+ if 'w' in mode:
83+ sendfile(local, remote, name)
84+ else:
85+ print "same mtime but different sum?!?!",
86+ print
87+ for name in lsumdict.keys():
88+ if not rsumdict.keys():
89+ print repr(name), "only locally",
90+ fl()
91+ if 'w' in mode and 'c' in mode:
92+ sendfile(local, remote, name)
93+ elif 'r' in mode and 'd' in mode:
94+ os.unlink(name)
95+ print "removed."
96+ print
97+ print "gettin subdirs ..."
98+ subdirs = remote._recv(subdirs_id)
99+ common = []
100+ for name in subdirs:
101+ if local.isdir(name):
102+ print "Common subdirectory", repr(name)
103+ common.append(name)
104+ else:
105+ print "Remote subdirectory", repr(name), "not found locally"
106+ if 'r' in mode and 'c' in mode:
107+ pr = "Create local subdirectory %s? [y] " % \
108+ repr(name)
109+ if 'y' in mode:
110+ ok = 'y'
111+ else:
112+ ok = ask(pr, "y")
113+ if ok[:1] in ('y', 'Y'):
114+ local.mkdir(name)
115+ print "Subdirectory %s made" % \
116+ repr(name)
117+ common.append(name)
118+ lsubdirs = local.listsubdirs()
119+ for name in lsubdirs:
120+ if name not in subdirs:
121+ print "Local subdirectory", repr(name), "not found remotely"
122+ for name in common:
123+ print "Entering subdirectory", repr(name)
124+ local.cd(name)
125+ remote.cd(name)
126+ compare(local, remote, mode)
127+ remote.back()
128+ local.back()
129+
130+def sendfile(local, remote, name):
131+ try:
132+ remote.create(name)
133+ except (IOError, os.error), msg:
134+ print "cannot create:", msg
135+ return
136+
137+ print "sending ...",
138+ fl()
139+
140+ data = open(name).read()
141+
142+ t1 = time.time()
143+
144+ remote._send_noreply('write', name, data)
145+ remote._flush()
146+
147+ t2 = time.time()
148+
149+ dt = t2-t1
150+ print len(data), "bytes in", round(dt), "seconds",
151+ if dt:
152+ print "i.e.", round(len(data)/dt), "bytes/sec",
153+ print
154+
155+def recvfile(local, remote, name):
156+ ok = 0
157+ try:
158+ rv = recvfile_real(local, remote, name)
159+ ok = 1
160+ return rv
161+ finally:
162+ if not ok:
163+ print "*** recvfile of %r failed, deleting" % (name,)
164+ local.delete(name)
165+
166+def recvfile_real(local, remote, name):
167+ try:
168+ local.create(name)
169+ except (IOError, os.error), msg:
170+ print "cannot create:", msg
171+ return
172+
173+ print "receiving ...",
174+ fl()
175+
176+ f = open(name, 'w')
177+ t1 = time.time()
178+
179+ length = 4*1024
180+ offset = 0
181+ id = remote._send('read', name, offset, length)
182+ remote._flush()
183+ while 1:
184+ newoffset = offset + length
185+ newid = remote._send('read', name, newoffset, length)
186+ data = remote._recv(id)
187+ id = newid
188+ if not data: break
189+ f.seek(offset)
190+ f.write(data)
191+ offset = newoffset
192+ size = f.tell()
193+
194+ t2 = time.time()
195+ f.close()
196+
197+ dt = t2-t1
198+ print size, "bytes in", round(dt), "seconds",
199+ if dt:
200+ print "i.e.", int(size/dt), "bytes/sec",
201+ print
202+ remote._recv(id) # ignored
203+
204+def fl():
205+ sys.stdout.flush()
206+
207+if __name__ == '__main__':
208+ main()
sys/src/cmd/python/Demo/pdist/cvslib.py+364−0
@@ -0,0 +1,364 @@
1+"""Utilities for CVS administration."""
2+
3+import string
4+import os
5+import time
6+import md5
7+import fnmatch
8+
9+if not hasattr(time, 'timezone'):
10+ time.timezone = 0
11+
12+class File:
13+
14+ """Represent a file's status.
15+
16+ Instance variables:
17+
18+ file -- the filename (no slashes), None if uninitialized
19+ lseen -- true if the data for the local file is up to date
20+ eseen -- true if the data from the CVS/Entries entry is up to date
21+ (this implies that the entry must be written back)
22+ rseen -- true if the data for the remote file is up to date
23+ proxy -- RCSProxy instance used to contact the server, or None
24+
25+ Note that lseen and rseen don't necessary mean that a local
26+ or remote file *exists* -- they indicate that we've checked it.
27+ However, eseen means that this instance corresponds to an
28+ entry in the CVS/Entries file.
29+
30+ If lseen is true:
31+
32+ lsum -- checksum of the local file, None if no local file
33+ lctime -- ctime of the local file, None if no local file
34+ lmtime -- mtime of the local file, None if no local file
35+
36+ If eseen is true:
37+
38+ erev -- revision, None if this is a no revision (not '0')
39+ enew -- true if this is an uncommitted added file
40+ edeleted -- true if this is an uncommitted removed file
41+ ectime -- ctime of last local file corresponding to erev
42+ emtime -- mtime of last local file corresponding to erev
43+ extra -- 5th string from CVS/Entries file
44+
45+ If rseen is true:
46+
47+ rrev -- revision of head, None if non-existent
48+ rsum -- checksum of that revision, Non if non-existent
49+
50+ If eseen and rseen are both true:
51+
52+ esum -- checksum of revision erev, None if no revision
53+
54+ Note
55+ """
56+
57+ def __init__(self, file = None):
58+ if file and '/' in file:
59+ raise ValueError, "no slash allowed in file"
60+ self.file = file
61+ self.lseen = self.eseen = self.rseen = 0
62+ self.proxy = None
63+
64+ def __cmp__(self, other):
65+ return cmp(self.file, other.file)
66+
67+ def getlocal(self):
68+ try:
69+ self.lmtime, self.lctime = os.stat(self.file)[-2:]
70+ except os.error:
71+ self.lmtime = self.lctime = self.lsum = None
72+ else:
73+ self.lsum = md5.new(open(self.file).read()).digest()
74+ self.lseen = 1
75+
76+ def getentry(self, line):
77+ words = string.splitfields(line, '/')
78+ if self.file and words[1] != self.file:
79+ raise ValueError, "file name mismatch"
80+ self.file = words[1]
81+ self.erev = words[2]
82+ self.edeleted = 0
83+ self.enew = 0
84+ self.ectime = self.emtime = None
85+ if self.erev[:1] == '-':
86+ self.edeleted = 1
87+ self.erev = self.erev[1:]
88+ if self.erev == '0':
89+ self.erev = None
90+ self.enew = 1
91+ else:
92+ dates = words[3]
93+ self.ectime = unctime(dates[:24])
94+ self.emtime = unctime(dates[25:])
95+ self.extra = words[4]
96+ if self.rseen:
97+ self.getesum()
98+ self.eseen = 1
99+
100+ def getremote(self, proxy = None):
101+ if proxy:
102+ self.proxy = proxy
103+ try:
104+ self.rrev = self.proxy.head(self.file)
105+ except (os.error, IOError):
106+ self.rrev = None
107+ if self.rrev:
108+ self.rsum = self.proxy.sum(self.file)
109+ else:
110+ self.rsum = None
111+ if self.eseen:
112+ self.getesum()
113+ self.rseen = 1
114+
115+ def getesum(self):
116+ if self.erev == self.rrev:
117+ self.esum = self.rsum
118+ elif self.erev:
119+ name = (self.file, self.erev)
120+ self.esum = self.proxy.sum(name)
121+ else:
122+ self.esum = None
123+
124+ def putentry(self):
125+ """Return a line suitable for inclusion in CVS/Entries.
126+
127+ The returned line is terminated by a newline.
128+ If no entry should be written for this file,
129+ return "".
130+ """
131+ if not self.eseen:
132+ return ""
133+
134+ rev = self.erev or '0'
135+ if self.edeleted:
136+ rev = '-' + rev
137+ if self.enew:
138+ dates = 'Initial ' + self.file
139+ else:
140+ dates = gmctime(self.ectime) + ' ' + \
141+ gmctime(self.emtime)
142+ return "/%s/%s/%s/%s/\n" % (
143+ self.file,
144+ rev,
145+ dates,
146+ self.extra)
147+
148+ def report(self):
149+ print '-'*50
150+ def r(key, repr=repr, self=self):
151+ try:
152+ value = repr(getattr(self, key))
153+ except AttributeError:
154+ value = "?"
155+ print "%-15s:" % key, value
156+ r("file")
157+ if self.lseen:
158+ r("lsum", hexify)
159+ r("lctime", gmctime)
160+ r("lmtime", gmctime)
161+ if self.eseen:
162+ r("erev")
163+ r("enew")
164+ r("edeleted")
165+ r("ectime", gmctime)
166+ r("emtime", gmctime)
167+ if self.rseen:
168+ r("rrev")
169+ r("rsum", hexify)
170+ if self.eseen:
171+ r("esum", hexify)
172+
173+
174+class CVS:
175+
176+ """Represent the contents of a CVS admin file (and more).
177+
178+ Class variables:
179+
180+ FileClass -- the class to be instantiated for entries
181+ (this should be derived from class File above)
182+ IgnoreList -- shell patterns for local files to be ignored
183+
184+ Instance variables:
185+
186+ entries -- a dictionary containing File instances keyed by
187+ their file name
188+ proxy -- an RCSProxy instance, or None
189+ """
190+
191+ FileClass = File
192+
193+ IgnoreList = ['.*', '@*', ',*', '*~', '*.o', '*.a', '*.so', '*.pyc']
194+
195+ def __init__(self):
196+ self.entries = {}
197+ self.proxy = None
198+
199+ def setproxy(self, proxy):
200+ if proxy is self.proxy:
201+ return
202+ self.proxy = proxy
203+ for e in self.entries.values():
204+ e.rseen = 0
205+
206+ def getentries(self):
207+ """Read the contents of CVS/Entries"""
208+ self.entries = {}
209+ f = self.cvsopen("Entries")
210+ while 1:
211+ line = f.readline()
212+ if not line: break
213+ e = self.FileClass()
214+ e.getentry(line)
215+ self.entries[e.file] = e
216+ f.close()
217+
218+ def putentries(self):
219+ """Write CVS/Entries back"""
220+ f = self.cvsopen("Entries", 'w')
221+ for e in self.values():
222+ f.write(e.putentry())
223+ f.close()
224+
225+ def getlocalfiles(self):
226+ list = self.entries.keys()
227+ addlist = os.listdir(os.curdir)
228+ for name in addlist:
229+ if name in list:
230+ continue
231+ if not self.ignored(name):
232+ list.append(name)
233+ list.sort()
234+ for file in list:
235+ try:
236+ e = self.entries[file]
237+ except KeyError:
238+ e = self.entries[file] = self.FileClass(file)
239+ e.getlocal()
240+
241+ def getremotefiles(self, proxy = None):
242+ if proxy:
243+ self.proxy = proxy
244+ if not self.proxy:
245+ raise RuntimeError, "no RCS proxy"
246+ addlist = self.proxy.listfiles()
247+ for file in addlist:
248+ try:
249+ e = self.entries[file]
250+ except KeyError:
251+ e = self.entries[file] = self.FileClass(file)
252+ e.getremote(self.proxy)
253+
254+ def report(self):
255+ for e in self.values():
256+ e.report()
257+ print '-'*50
258+
259+ def keys(self):
260+ keys = self.entries.keys()
261+ keys.sort()
262+ return keys
263+
264+ def values(self):
265+ def value(key, self=self):
266+ return self.entries[key]
267+ return map(value, self.keys())
268+
269+ def items(self):
270+ def item(key, self=self):
271+ return (key, self.entries[key])
272+ return map(item, self.keys())
273+
274+ def cvsexists(self, file):
275+ file = os.path.join("CVS", file)
276+ return os.path.exists(file)
277+
278+ def cvsopen(self, file, mode = 'r'):
279+ file = os.path.join("CVS", file)
280+ if 'r' not in mode:
281+ self.backup(file)
282+ return open(file, mode)
283+
284+ def backup(self, file):
285+ if os.path.isfile(file):
286+ bfile = file + '~'
287+ try: os.unlink(bfile)
288+ except os.error: pass
289+ os.rename(file, bfile)
290+
291+ def ignored(self, file):
292+ if os.path.isdir(file): return True
293+ for pat in self.IgnoreList:
294+ if fnmatch.fnmatch(file, pat): return True
295+ return False
296+
297+
298+# hexify and unhexify are useful to print MD5 checksums in hex format
299+
300+hexify_format = '%02x' * 16
301+def hexify(sum):
302+ "Return a hex representation of a 16-byte string (e.g. an MD5 digest)"
303+ if sum is None:
304+ return "None"
305+ return hexify_format % tuple(map(ord, sum))
306+
307+def unhexify(hexsum):
308+ "Return the original from a hexified string"
309+ if hexsum == "None":
310+ return None
311+ sum = ''
312+ for i in range(0, len(hexsum), 2):
313+ sum = sum + chr(string.atoi(hexsum[i:i+2], 16))
314+ return sum
315+
316+
317+unctime_monthmap = {}
318+def unctime(date):
319+ if date == "None": return None
320+ if not unctime_monthmap:
321+ months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
322+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
323+ i = 0
324+ for m in months:
325+ i = i+1
326+ unctime_monthmap[m] = i
327+ words = string.split(date) # Day Mon DD HH:MM:SS YEAR
328+ year = string.atoi(words[4])
329+ month = unctime_monthmap[words[1]]
330+ day = string.atoi(words[2])
331+ [hh, mm, ss] = map(string.atoi, string.splitfields(words[3], ':'))
332+ ss = ss - time.timezone
333+ return time.mktime((year, month, day, hh, mm, ss, 0, 0, 0))
334+
335+def gmctime(t):
336+ if t is None: return "None"
337+ return time.asctime(time.gmtime(t))
338+
339+def test_unctime():
340+ now = int(time.time())
341+ t = time.gmtime(now)
342+ at = time.asctime(t)
343+ print 'GMT', now, at
344+ print 'timezone', time.timezone
345+ print 'local', time.ctime(now)
346+ u = unctime(at)
347+ print 'unctime()', u
348+ gu = time.gmtime(u)
349+ print '->', gu
350+ print time.asctime(gu)
351+
352+def test():
353+ x = CVS()
354+ x.getentries()
355+ x.getlocalfiles()
356+## x.report()
357+ import rcsclient
358+ proxy = rcsclient.openrcsclient()
359+ x.getremotefiles(proxy)
360+ x.report()
361+
362+
363+if __name__ == "__main__":
364+ test()
sys/src/cmd/python/Demo/pdist/cvslock.py+280−0
@@ -0,0 +1,280 @@
1+"""CVS locking algorithm.
2+
3+CVS locking strategy
4+====================
5+
6+As reverse engineered from the CVS 1.3 sources (file lock.c):
7+
8+- Locking is done on a per repository basis (but a process can hold
9+write locks for multiple directories); all lock files are placed in
10+the repository and have names beginning with "#cvs.".
11+
12+- Before even attempting to lock, a file "#cvs.tfl.<pid>" is created
13+(and removed again), to test that we can write the repository. [The
14+algorithm can still be fooled (1) if the repository's mode is changed
15+while attempting to lock; (2) if this file exists and is writable but
16+the directory is not.]
17+
18+- While creating the actual read/write lock files (which may exist for
19+a long time), a "meta-lock" is held. The meta-lock is a directory
20+named "#cvs.lock" in the repository. The meta-lock is also held while
21+a write lock is held.
22+
23+- To set a read lock:
24+
25+ - acquire the meta-lock
26+ - create the file "#cvs.rfl.<pid>"
27+ - release the meta-lock
28+
29+- To set a write lock:
30+
31+ - acquire the meta-lock
32+ - check that there are no files called "#cvs.rfl.*"
33+ - if there are, release the meta-lock, sleep, try again
34+ - create the file "#cvs.wfl.<pid>"
35+
36+- To release a write lock:
37+
38+ - remove the file "#cvs.wfl.<pid>"
39+ - rmdir the meta-lock
40+
41+- To release a read lock:
42+
43+ - remove the file "#cvs.rfl.<pid>"
44+
45+
46+Additional notes
47+----------------
48+
49+- A process should read-lock at most one repository at a time.
50+
51+- A process may write-lock as many repositories as it wishes (to avoid
52+deadlocks, I presume it should always lock them top-down in the
53+directory hierarchy).
54+
55+- A process should make sure it removes all its lock files and
56+directories when it crashes.
57+
58+- Limitation: one user id should not be committing files into the same
59+repository at the same time.
60+
61+
62+Turn this into Python code
63+--------------------------
64+
65+rl = ReadLock(repository, waittime)
66+
67+wl = WriteLock(repository, waittime)
68+
69+list = MultipleWriteLock([repository1, repository2, ...], waittime)
70+
71+"""
72+
73+
74+import os
75+import time
76+import stat
77+import pwd
78+
79+
80+# Default wait time
81+DELAY = 10
82+
83+
84+# XXX This should be the same on all Unix versions
85+EEXIST = 17
86+
87+
88+# Files used for locking (must match cvs.h in the CVS sources)
89+CVSLCK = "#cvs.lck"
90+CVSRFL = "#cvs.rfl."
91+CVSWFL = "#cvs.wfl."
92+
93+
94+class Error:
95+
96+ def __init__(self, msg):
97+ self.msg = msg
98+
99+ def __repr__(self):
100+ return repr(self.msg)
101+
102+ def __str__(self):
103+ return str(self.msg)
104+
105+
106+class Locked(Error):
107+ pass
108+
109+
110+class Lock:
111+
112+ def __init__(self, repository = ".", delay = DELAY):
113+ self.repository = repository
114+ self.delay = delay
115+ self.lockdir = None
116+ self.lockfile = None
117+ pid = repr(os.getpid())
118+ self.cvslck = self.join(CVSLCK)
119+ self.cvsrfl = self.join(CVSRFL + pid)
120+ self.cvswfl = self.join(CVSWFL + pid)
121+
122+ def __del__(self):
123+ print "__del__"
124+ self.unlock()
125+
126+ def setlockdir(self):
127+ while 1:
128+ try:
129+ self.lockdir = self.cvslck
130+ os.mkdir(self.cvslck, 0777)
131+ return
132+ except os.error, msg:
133+ self.lockdir = None
134+ if msg[0] == EEXIST:
135+ try:
136+ st = os.stat(self.cvslck)
137+ except os.error:
138+ continue
139+ self.sleep(st)
140+ continue
141+ raise Error("failed to lock %s: %s" % (
142+ self.repository, msg))
143+
144+ def unlock(self):
145+ self.unlockfile()
146+ self.unlockdir()
147+
148+ def unlockfile(self):
149+ if self.lockfile:
150+ print "unlink", self.lockfile
151+ try:
152+ os.unlink(self.lockfile)
153+ except os.error:
154+ pass
155+ self.lockfile = None
156+
157+ def unlockdir(self):
158+ if self.lockdir:
159+ print "rmdir", self.lockdir
160+ try:
161+ os.rmdir(self.lockdir)
162+ except os.error:
163+ pass
164+ self.lockdir = None
165+
166+ def sleep(self, st):
167+ sleep(st, self.repository, self.delay)
168+
169+ def join(self, name):
170+ return os.path.join(self.repository, name)
171+
172+
173+def sleep(st, repository, delay):
174+ if delay <= 0:
175+ raise Locked(st)
176+ uid = st[stat.ST_UID]
177+ try:
178+ pwent = pwd.getpwuid(uid)
179+ user = pwent[0]
180+ except KeyError:
181+ user = "uid %d" % uid
182+ print "[%s]" % time.ctime(time.time())[11:19],
183+ print "Waiting for %s's lock in" % user, repository
184+ time.sleep(delay)
185+
186+
187+class ReadLock(Lock):
188+
189+ def __init__(self, repository, delay = DELAY):
190+ Lock.__init__(self, repository, delay)
191+ ok = 0
192+ try:
193+ self.setlockdir()
194+ self.lockfile = self.cvsrfl
195+ fp = open(self.lockfile, 'w')
196+ fp.close()
197+ ok = 1
198+ finally:
199+ if not ok:
200+ self.unlockfile()
201+ self.unlockdir()
202+
203+
204+class WriteLock(Lock):
205+
206+ def __init__(self, repository, delay = DELAY):
207+ Lock.__init__(self, repository, delay)
208+ self.setlockdir()
209+ while 1:
210+ uid = self.readers_exist()
211+ if not uid:
212+ break
213+ self.unlockdir()
214+ self.sleep(uid)
215+ self.lockfile = self.cvswfl
216+ fp = open(self.lockfile, 'w')
217+ fp.close()
218+
219+ def readers_exist(self):
220+ n = len(CVSRFL)
221+ for name in os.listdir(self.repository):
222+ if name[:n] == CVSRFL:
223+ try:
224+ st = os.stat(self.join(name))
225+ except os.error:
226+ continue
227+ return st
228+ return None
229+
230+
231+def MultipleWriteLock(repositories, delay = DELAY):
232+ while 1:
233+ locks = []
234+ for r in repositories:
235+ try:
236+ locks.append(WriteLock(r, 0))
237+ except Locked, instance:
238+ del locks
239+ break
240+ else:
241+ break
242+ sleep(instance.msg, r, delay)
243+ return list
244+
245+
246+def test():
247+ import sys
248+ if sys.argv[1:]:
249+ repository = sys.argv[1]
250+ else:
251+ repository = "."
252+ rl = None
253+ wl = None
254+ try:
255+ print "attempting write lock ..."
256+ wl = WriteLock(repository)
257+ print "got it."
258+ wl.unlock()
259+ print "attempting read lock ..."
260+ rl = ReadLock(repository)
261+ print "got it."
262+ rl.unlock()
263+ finally:
264+ print [1]
265+ sys.exc_traceback = None
266+ print [2]
267+ if rl:
268+ rl.unlock()
269+ print [3]
270+ if wl:
271+ wl.unlock()
272+ print [4]
273+ rl = None
274+ print [5]
275+ wl = None
276+ print [6]
277+
278+
279+if __name__ == '__main__':
280+ test()
sys/src/cmd/python/Demo/pdist/mac.py+19−0
@@ -0,0 +1,19 @@
1+import sys
2+import string
3+import rcvs
4+
5+def main():
6+ while 1:
7+ try:
8+ line = raw_input('$ ')
9+ except EOFError:
10+ break
11+ words = string.split(line)
12+ if not words:
13+ continue
14+ if words[0] != 'rcvs':
15+ words.insert(0, 'rcvs')
16+ sys.argv = words
17+ rcvs.main()
18+
19+main()
sys/src/cmd/python/Demo/pdist/makechangelog.py+109−0
@@ -0,0 +1,109 @@
1+#! /usr/bin/env python
2+
3+"""Turn a pile of RCS log output into ChangeLog file entries.
4+
5+"""
6+
7+import sys
8+import string
9+import re
10+import getopt
11+import time
12+
13+def main():
14+ args = sys.argv[1:]
15+ opts, args = getopt.getopt(args, 'p:')
16+ prefix = ''
17+ for o, a in opts:
18+ if p == '-p': prefix = a
19+
20+ f = sys.stdin
21+ allrevs = []
22+ while 1:
23+ file = getnextfile(f)
24+ if not file: break
25+ revs = []
26+ while 1:
27+ rev = getnextrev(f, file)
28+ if not rev:
29+ break
30+ revs.append(rev)
31+ if revs:
32+ allrevs[len(allrevs):] = revs
33+ allrevs.sort()
34+ allrevs.reverse()
35+ for rev in allrevs:
36+ formatrev(rev, prefix)
37+
38+parsedateprog = re.compile(
39+ '^date: ([0-9]+)/([0-9]+)/([0-9]+) ' +
40+ '([0-9]+):([0-9]+):([0-9]+); author: ([^ ;]+)')
41+
42+authormap = {
43+ 'guido': 'Guido van Rossum <guido@cnri.reston.va.us>',
44+ 'jack': 'Jack Jansen <jack@cwi.nl>',
45+ 'sjoerd': 'Sjoerd Mullender <sjoerd@cwi.nl>',
46+ }
47+
48+def formatrev(rev, prefix):
49+ dateline, file, revline, log = rev
50+ if parsedateprog.match(dateline) >= 0:
51+ fields = parsedateprog.group(1, 2, 3, 4, 5, 6)
52+ author = parsedateprog.group(7)
53+ if authormap.has_key(author): author = authormap[author]
54+ tfields = map(string.atoi, fields) + [0, 0, 0]
55+ tfields[5] = tfields[5] - time.timezone
56+ t = time.mktime(tuple(tfields))
57+ print time.ctime(t), '', author
58+ words = string.split(log)
59+ words[:0] = ['*', prefix + file + ':']
60+ maxcol = 72-8
61+ col = maxcol
62+ for word in words:
63+ if col > 0 and col + len(word) >= maxcol:
64+ print
65+ print '\t' + word,
66+ col = -1
67+ else:
68+ print word,
69+ col = col + 1 + len(word)
70+ print
71+ print
72+
73+startprog = re.compile("^Working file: (.*)$")
74+
75+def getnextfile(f):
76+ while 1:
77+ line = f.readline()
78+ if not line: return None
79+ if startprog.match(line) >= 0:
80+ file = startprog.group(1)
81+ # Skip until first revision
82+ while 1:
83+ line = f.readline()
84+ if not line: return None
85+ if line[:10] == '='*10: return None
86+ if line[:10] == '-'*10: break
87+## print "Skipped", line,
88+ return file
89+## else:
90+## print "Ignored", line,
91+
92+def getnextrev(f, file):
93+ # This is called when we are positioned just after a '---' separator
94+ revline = f.readline()
95+ dateline = f.readline()
96+ log = ''
97+ while 1:
98+ line = f.readline()
99+ if not line: break
100+ if line[:10] == '='*10:
101+ # Ignore the *last* log entry for each file since it
102+ # is the revision since which we are logging.
103+ return None
104+ if line[:10] == '-'*10: break
105+ log = log + line
106+ return dateline, file, revline, log
107+
108+if __name__ == '__main__':
109+ main()
sys/src/cmd/python/Demo/pdist/rcsbump+33−0
@@ -0,0 +1,33 @@
1+#!/usr/bin/env python
2+# -*- python -*-
3+#
4+# guido's version, from rcsbump,v 1.2 1995/06/22 21:27:27 bwarsaw Exp
5+#
6+# Python script for bumping up an RCS major revision number.
7+
8+import sys
9+import re
10+import rcslib
11+import string
12+
13+WITHLOCK = 1
14+majorrev_re = re.compile('^[0-9]+')
15+
16+dir = rcslib.RCS()
17+
18+if sys.argv[1:]:
19+ files = sys.argv[1:]
20+else:
21+ files = dir.listfiles()
22+
23+for file in files:
24+ # get the major revnumber of the file
25+ headbranch = dir.info(file)['head']
26+ majorrev_re.match(headbranch)
27+ majorrev = string.atoi(majorrev_re.group(0)) + 1
28+
29+ if not dir.islocked(file):
30+ dir.checkout(file, WITHLOCK)
31+
32+ msg = "Bumping major revision number (to %d)" % majorrev
33+ dir.checkin((file, "%s.0" % majorrev), msg, "-f")
sys/src/cmd/python/Demo/pdist/rcsclient.py+71−0
@@ -0,0 +1,71 @@
1+"""Customize this file to change the default client etc.
2+
3+(In general, it is probably be better to make local operation the
4+default and to require something like an RCSSERVER environment
5+variable to enable remote operation.)
6+
7+"""
8+
9+import string
10+import os
11+
12+# These defaults don't belong here -- they should be taken from the
13+# environment or from a hidden file in the current directory
14+
15+HOST = 'voorn.cwi.nl'
16+PORT = 4127
17+VERBOSE = 1
18+LOCAL = 0
19+
20+import client
21+
22+
23+class RCSProxyClient(client.SecureClient):
24+
25+ def __init__(self, address, verbose = client.VERBOSE):
26+ client.SecureClient.__init__(self, address, verbose)
27+
28+
29+def openrcsclient(opts = []):
30+ "open an RCSProxy client based on a list of options returned by getopt"
31+ import RCSProxy
32+ host = HOST
33+ port = PORT
34+ verbose = VERBOSE
35+ local = LOCAL
36+ directory = None
37+ for o, a in opts:
38+ if o == '-h':
39+ host = a
40+ if ':' in host:
41+ i = string.find(host, ':')
42+ host, p = host[:i], host[i+1:]
43+ if p:
44+ port = string.atoi(p)
45+ if o == '-p':
46+ port = string.atoi(a)
47+ if o == '-d':
48+ directory = a
49+ if o == '-v':
50+ verbose = verbose + 1
51+ if o == '-q':
52+ verbose = 0
53+ if o == '-L':
54+ local = 1
55+ if local:
56+ import RCSProxy
57+ x = RCSProxy.RCSProxyLocal()
58+ else:
59+ address = (host, port)
60+ x = RCSProxyClient(address, verbose)
61+ if not directory:
62+ try:
63+ directory = open(os.path.join("CVS", "Repository")).readline()
64+ except IOError:
65+ pass
66+ else:
67+ if directory[-1] == '\n':
68+ directory = directory[:-1]
69+ if directory:
70+ x.cd(directory)
71+ return x
sys/src/cmd/python/Demo/pdist/rcslib.py+334−0
@@ -0,0 +1,334 @@
1+"""RCS interface module.
2+
3+Defines the class RCS, which represents a directory with rcs version
4+files and (possibly) corresponding work files.
5+
6+"""
7+
8+
9+import fnmatch
10+import os
11+import re
12+import string
13+import tempfile
14+
15+
16+class RCS:
17+
18+ """RCS interface class (local filesystem version).
19+
20+ An instance of this class represents a directory with rcs version
21+ files and (possible) corresponding work files.
22+
23+ Methods provide access to most rcs operations such as
24+ checkin/checkout, access to the rcs metadata (revisions, logs,
25+ branches etc.) as well as some filesystem operations such as
26+ listing all rcs version files.
27+
28+ XXX BUGS / PROBLEMS
29+
30+ - The instance always represents the current directory so it's not
31+ very useful to have more than one instance around simultaneously
32+
33+ """
34+
35+ # Characters allowed in work file names
36+ okchars = string.ascii_letters + string.digits + '-_=+'
37+
38+ def __init__(self):
39+ """Constructor."""
40+ pass
41+
42+ def __del__(self):
43+ """Destructor."""
44+ pass
45+
46+ # --- Informational methods about a single file/revision ---
47+
48+ def log(self, name_rev, otherflags = ''):
49+ """Return the full log text for NAME_REV as a string.
50+
51+ Optional OTHERFLAGS are passed to rlog.
52+
53+ """
54+ f = self._open(name_rev, 'rlog ' + otherflags)
55+ data = f.read()
56+ status = self._closepipe(f)
57+ if status:
58+ data = data + "%s: %s" % status
59+ elif data[-1] == '\n':
60+ data = data[:-1]
61+ return data
62+
63+ def head(self, name_rev):
64+ """Return the head revision for NAME_REV"""
65+ dict = self.info(name_rev)
66+ return dict['head']
67+
68+ def info(self, name_rev):
69+ """Return a dictionary of info (from rlog -h) for NAME_REV
70+
71+ The dictionary's keys are the keywords that rlog prints
72+ (e.g. 'head' and its values are the corresponding data
73+ (e.g. '1.3').
74+
75+ XXX symbolic names and locks are not returned
76+
77+ """
78+ f = self._open(name_rev, 'rlog -h')
79+ dict = {}
80+ while 1:
81+ line = f.readline()
82+ if not line: break
83+ if line[0] == '\t':
84+ # XXX could be a lock or symbolic name
85+ # Anything else?
86+ continue
87+ i = string.find(line, ':')
88+ if i > 0:
89+ key, value = line[:i], string.strip(line[i+1:])
90+ dict[key] = value
91+ status = self._closepipe(f)
92+ if status:
93+ raise IOError, status
94+ return dict
95+
96+ # --- Methods that change files ---
97+
98+ def lock(self, name_rev):
99+ """Set an rcs lock on NAME_REV."""
100+ name, rev = self.checkfile(name_rev)
101+ cmd = "rcs -l%s %s" % (rev, name)
102+ return self._system(cmd)
103+
104+ def unlock(self, name_rev):
105+ """Clear an rcs lock on NAME_REV."""
106+ name, rev = self.checkfile(name_rev)
107+ cmd = "rcs -u%s %s" % (rev, name)
108+ return self._system(cmd)
109+
110+ def checkout(self, name_rev, withlock=0, otherflags=""):
111+ """Check out NAME_REV to its work file.
112+
113+ If optional WITHLOCK is set, check out locked, else unlocked.
114+
115+ The optional OTHERFLAGS is passed to co without
116+ interpretation.
117+
118+ Any output from co goes to directly to stdout.
119+
120+ """
121+ name, rev = self.checkfile(name_rev)
122+ if withlock: lockflag = "-l"
123+ else: lockflag = "-u"
124+ cmd = 'co %s%s %s %s' % (lockflag, rev, otherflags, name)
125+ return self._system(cmd)
126+
127+ def checkin(self, name_rev, message=None, otherflags=""):
128+ """Check in NAME_REV from its work file.
129+
130+ The optional MESSAGE argument becomes the checkin message
131+ (default "<none>" if None); or the file description if this is
132+ a new file.
133+
134+ The optional OTHERFLAGS argument is passed to ci without
135+ interpretation.
136+
137+ Any output from ci goes to directly to stdout.
138+
139+ """
140+ name, rev = self._unmangle(name_rev)
141+ new = not self.isvalid(name)
142+ if not message: message = "<none>"
143+ if message and message[-1] != '\n':
144+ message = message + '\n'
145+ lockflag = "-u"
146+ if new:
147+ f = tempfile.NamedTemporaryFile()
148+ f.write(message)
149+ f.flush()
150+ cmd = 'ci %s%s -t%s %s %s' % \
151+ (lockflag, rev, f.name, otherflags, name)
152+ else:
153+ message = re.sub(r'([\"$`])', r'\\\1', message)
154+ cmd = 'ci %s%s -m"%s" %s %s' % \
155+ (lockflag, rev, message, otherflags, name)
156+ return self._system(cmd)
157+
158+ # --- Exported support methods ---
159+
160+ def listfiles(self, pat = None):
161+ """Return a list of all version files matching optional PATTERN."""
162+ files = os.listdir(os.curdir)
163+ files = filter(self._isrcs, files)
164+ if os.path.isdir('RCS'):
165+ files2 = os.listdir('RCS')
166+ files2 = filter(self._isrcs, files2)
167+ files = files + files2
168+ files = map(self.realname, files)
169+ return self._filter(files, pat)
170+
171+ def isvalid(self, name):
172+ """Test whether NAME has a version file associated."""
173+ namev = self.rcsname(name)
174+ return (os.path.isfile(namev) or
175+ os.path.isfile(os.path.join('RCS', namev)))
176+
177+ def rcsname(self, name):
178+ """Return the pathname of the version file for NAME.
179+
180+ The argument can be a work file name or a version file name.
181+ If the version file does not exist, the name of the version
182+ file that would be created by "ci" is returned.
183+
184+ """
185+ if self._isrcs(name): namev = name
186+ else: namev = name + ',v'
187+ if os.path.isfile(namev): return namev
188+ namev = os.path.join('RCS', os.path.basename(namev))
189+ if os.path.isfile(namev): return namev
190+ if os.path.isdir('RCS'):
191+ return os.path.join('RCS', namev)
192+ else:
193+ return namev
194+
195+ def realname(self, namev):
196+ """Return the pathname of the work file for NAME.
197+
198+ The argument can be a work file name or a version file name.
199+ If the work file does not exist, the name of the work file
200+ that would be created by "co" is returned.
201+
202+ """
203+ if self._isrcs(namev): name = namev[:-2]
204+ else: name = namev
205+ if os.path.isfile(name): return name
206+ name = os.path.basename(name)
207+ return name
208+
209+ def islocked(self, name_rev):
210+ """Test whether FILE (which must have a version file) is locked.
211+
212+ XXX This does not tell you which revision number is locked and
213+ ignores any revision you may pass in (by virtue of using rlog
214+ -L -R).
215+
216+ """
217+ f = self._open(name_rev, 'rlog -L -R')
218+ line = f.readline()
219+ status = self._closepipe(f)
220+ if status:
221+ raise IOError, status
222+ if not line: return None
223+ if line[-1] == '\n':
224+ line = line[:-1]
225+ return self.realname(name_rev) == self.realname(line)
226+
227+ def checkfile(self, name_rev):
228+ """Normalize NAME_REV into a (NAME, REV) tuple.
229+
230+ Raise an exception if there is no corresponding version file.
231+
232+ """
233+ name, rev = self._unmangle(name_rev)
234+ if not self.isvalid(name):
235+ raise os.error, 'not an rcs file %r' % (name,)
236+ return name, rev
237+
238+ # --- Internal methods ---
239+
240+ def _open(self, name_rev, cmd = 'co -p', rflag = '-r'):
241+ """INTERNAL: open a read pipe to NAME_REV using optional COMMAND.
242+
243+ Optional FLAG is used to indicate the revision (default -r).
244+
245+ Default COMMAND is "co -p".
246+
247+ Return a file object connected by a pipe to the command's
248+ output.
249+
250+ """
251+ name, rev = self.checkfile(name_rev)
252+ namev = self.rcsname(name)
253+ if rev:
254+ cmd = cmd + ' ' + rflag + rev
255+ return os.popen("%s %r" % (cmd, namev))
256+
257+ def _unmangle(self, name_rev):
258+ """INTERNAL: Normalize NAME_REV argument to (NAME, REV) tuple.
259+
260+ Raise an exception if NAME contains invalid characters.
261+
262+ A NAME_REV argument is either NAME string (implying REV='') or
263+ a tuple of the form (NAME, REV).
264+
265+ """
266+ if type(name_rev) == type(''):
267+ name_rev = name, rev = name_rev, ''
268+ else:
269+ name, rev = name_rev
270+ for c in rev:
271+ if c not in self.okchars:
272+ raise ValueError, "bad char in rev"
273+ return name_rev
274+
275+ def _closepipe(self, f):
276+ """INTERNAL: Close PIPE and print its exit status if nonzero."""
277+ sts = f.close()
278+ if not sts: return None
279+ detail, reason = divmod(sts, 256)
280+ if reason == 0: return 'exit', detail # Exit status
281+ signal = reason&0x7F
282+ if signal == 0x7F:
283+ code = 'stopped'
284+ signal = detail
285+ else:
286+ code = 'killed'
287+ if reason&0x80:
288+ code = code + '(coredump)'
289+ return code, signal
290+
291+ def _system(self, cmd):
292+ """INTERNAL: run COMMAND in a subshell.
293+
294+ Standard input for the command is taken from /dev/null.
295+
296+ Raise IOError when the exit status is not zero.
297+
298+ Return whatever the calling method should return; normally
299+ None.
300+
301+ A derived class may override this method and redefine it to
302+ capture stdout/stderr of the command and return it.
303+
304+ """
305+ cmd = cmd + " </dev/null"
306+ sts = os.system(cmd)
307+ if sts: raise IOError, "command exit status %d" % sts
308+
309+ def _filter(self, files, pat = None):
310+ """INTERNAL: Return a sorted copy of the given list of FILES.
311+
312+ If a second PATTERN argument is given, only files matching it
313+ are kept. No check for valid filenames is made.
314+
315+ """
316+ if pat:
317+ def keep(name, pat = pat):
318+ return fnmatch.fnmatch(name, pat)
319+ files = filter(keep, files)
320+ else:
321+ files = files[:]
322+ files.sort()
323+ return files
324+
325+ def _remove(self, fn):
326+ """INTERNAL: remove FILE without complaints."""
327+ try:
328+ os.unlink(fn)
329+ except os.error:
330+ pass
331+
332+ def _isrcs(self, name):
333+ """INTERNAL: Test whether NAME ends in ',v'."""
334+ return name[-2:] == ',v'
sys/src/cmd/python/Demo/pdist/rcvs+8−0
@@ -0,0 +1,8 @@
1+#!/usr/bin/env python
2+
3+import addpack
4+addpack.addpack('/home/guido/src/python/Demo/pdist')
5+
6+import rcvs
7+
8+rcvs.main()
sys/src/cmd/python/Demo/pdist/rcvs.py+477−0
@@ -0,0 +1,477 @@
1+#! /usr/bin/env python
2+
3+"""Remote CVS -- command line interface"""
4+
5+# XXX To do:
6+#
7+# Bugs:
8+# - if the remote file is deleted, "rcvs update" will fail
9+#
10+# Functionality:
11+# - cvs rm
12+# - descend into directories (alraedy done for update)
13+# - conflict resolution
14+# - other relevant commands?
15+# - branches
16+#
17+# - Finesses:
18+# - retain file mode's x bits
19+# - complain when "nothing known about filename"
20+# - edit log message the way CVS lets you edit it
21+# - cvs diff -rREVA -rREVB
22+# - send mail the way CVS sends it
23+#
24+# Performance:
25+# - cache remote checksums (for every revision ever seen!)
26+# - translate symbolic revisions to numeric revisions
27+#
28+# Reliability:
29+# - remote locking
30+#
31+# Security:
32+# - Authenticated RPC?
33+
34+
35+from cvslib import CVS, File
36+import md5
37+import os
38+import string
39+import sys
40+from cmdfw import CommandFrameWork
41+
42+
43+DEF_LOCAL = 1 # Default -l
44+
45+
46+class MyFile(File):
47+
48+ def action(self):
49+ """Return a code indicating the update status of this file.
50+
51+ The possible return values are:
52+
53+ '=' -- everything's fine
54+ '0' -- file doesn't exist anywhere
55+ '?' -- exists locally only
56+ 'A' -- new locally
57+ 'R' -- deleted locally
58+ 'U' -- changed remotely, no changes locally
59+ (includes new remotely or deleted remotely)
60+ 'M' -- changed locally, no changes remotely
61+ 'C' -- conflict: changed locally as well as remotely
62+ (includes cases where the file has been added
63+ or removed locally and remotely)
64+ 'D' -- deleted remotely
65+ 'N' -- new remotely
66+ 'r' -- get rid of entry
67+ 'c' -- create entry
68+ 'u' -- update entry
69+
70+ (and probably others :-)
71+ """
72+ if not self.lseen:
73+ self.getlocal()
74+ if not self.rseen:
75+ self.getremote()
76+ if not self.eseen:
77+ if not self.lsum:
78+ if not self.rsum: return '0' # Never heard of
79+ else:
80+ return 'N' # New remotely
81+ else: # self.lsum
82+ if not self.rsum: return '?' # Local only
83+ # Local and remote, but no entry
84+ if self.lsum == self.rsum:
85+ return 'c' # Restore entry only
86+ else: return 'C' # Real conflict
87+ else: # self.eseen
88+ if not self.lsum:
89+ if self.edeleted:
90+ if self.rsum: return 'R' # Removed
91+ else: return 'r' # Get rid of entry
92+ else: # not self.edeleted
93+ if self.rsum:
94+ print "warning:",
95+ print self.file,
96+ print "was lost"
97+ return 'U'
98+ else: return 'r' # Get rid of entry
99+ else: # self.lsum
100+ if not self.rsum:
101+ if self.enew: return 'A' # New locally
102+ else: return 'D' # Deleted remotely
103+ else: # self.rsum
104+ if self.enew:
105+ if self.lsum == self.rsum:
106+ return 'u'
107+ else:
108+ return 'C'
109+ if self.lsum == self.esum:
110+ if self.esum == self.rsum:
111+ return '='
112+ else:
113+ return 'U'
114+ elif self.esum == self.rsum:
115+ return 'M'
116+ elif self.lsum == self.rsum:
117+ return 'u'
118+ else:
119+ return 'C'
120+
121+ def update(self):
122+ code = self.action()
123+ if code == '=': return
124+ print code, self.file
125+ if code in ('U', 'N'):
126+ self.get()
127+ elif code == 'C':
128+ print "%s: conflict resolution not yet implemented" % \
129+ self.file
130+ elif code == 'D':
131+ remove(self.file)
132+ self.eseen = 0
133+ elif code == 'r':
134+ self.eseen = 0
135+ elif code in ('c', 'u'):
136+ self.eseen = 1
137+ self.erev = self.rrev
138+ self.enew = 0
139+ self.edeleted = 0
140+ self.esum = self.rsum
141+ self.emtime, self.ectime = os.stat(self.file)[-2:]
142+ self.extra = ''
143+
144+ def commit(self, message = ""):
145+ code = self.action()
146+ if code in ('A', 'M'):
147+ self.put(message)
148+ return 1
149+ elif code == 'R':
150+ print "%s: committing removes not yet implemented" % \
151+ self.file
152+ elif code == 'C':
153+ print "%s: conflict resolution not yet implemented" % \
154+ self.file
155+
156+ def diff(self, opts = []):
157+ self.action() # To update lseen, rseen
158+ flags = ''
159+ rev = self.rrev
160+ # XXX should support two rev options too!
161+ for o, a in opts:
162+ if o == '-r':
163+ rev = a
164+ else:
165+ flags = flags + ' ' + o + a
166+ if rev == self.rrev and self.lsum == self.rsum:
167+ return
168+ flags = flags[1:]
169+ fn = self.file
170+ data = self.proxy.get((fn, rev))
171+ sum = md5.new(data).digest()
172+ if self.lsum == sum:
173+ return
174+ import tempfile
175+ tf = tempfile.NamedTemporaryFile()
176+ tf.write(data)
177+ tf.flush()
178+ print 'diff %s -r%s %s' % (flags, rev, fn)
179+ sts = os.system('diff %s %s %s' % (flags, tf.name, fn))
180+ if sts:
181+ print '='*70
182+
183+ def commitcheck(self):
184+ return self.action() != 'C'
185+
186+ def put(self, message = ""):
187+ print "Checking in", self.file, "..."
188+ data = open(self.file).read()
189+ if not self.enew:
190+ self.proxy.lock(self.file)
191+ messages = self.proxy.put(self.file, data, message)
192+ if messages:
193+ print messages
194+ self.setentry(self.proxy.head(self.file), self.lsum)
195+
196+ def get(self):
197+ data = self.proxy.get(self.file)
198+ f = open(self.file, 'w')
199+ f.write(data)
200+ f.close()
201+ self.setentry(self.rrev, self.rsum)
202+
203+ def log(self, otherflags):
204+ print self.proxy.log(self.file, otherflags)
205+
206+ def add(self):
207+ self.eseen = 0 # While we're hacking...
208+ self.esum = self.lsum
209+ self.emtime, self.ectime = 0, 0
210+ self.erev = ''
211+ self.enew = 1
212+ self.edeleted = 0
213+ self.eseen = 1 # Done
214+ self.extra = ''
215+
216+ def setentry(self, erev, esum):
217+ self.eseen = 0 # While we're hacking...
218+ self.esum = esum
219+ self.emtime, self.ectime = os.stat(self.file)[-2:]
220+ self.erev = erev
221+ self.enew = 0
222+ self.edeleted = 0
223+ self.eseen = 1 # Done
224+ self.extra = ''
225+
226+
227+SENDMAIL = "/usr/lib/sendmail -t"
228+MAILFORM = """To: %s
229+Subject: CVS changes: %s
230+
231+...Message from rcvs...
232+
233+Committed files:
234+ %s
235+
236+Log message:
237+ %s
238+"""
239+
240+
241+class RCVS(CVS):
242+
243+ FileClass = MyFile
244+
245+ def __init__(self):
246+ CVS.__init__(self)
247+
248+ def update(self, files):
249+ for e in self.whichentries(files, 1):
250+ e.update()
251+
252+ def commit(self, files, message = ""):
253+ list = self.whichentries(files)
254+ if not list: return
255+ ok = 1
256+ for e in list:
257+ if not e.commitcheck():
258+ ok = 0
259+ if not ok:
260+ print "correct above errors first"
261+ return
262+ if not message:
263+ message = raw_input("One-liner: ")
264+ committed = []
265+ for e in list:
266+ if e.commit(message):
267+ committed.append(e.file)
268+ self.mailinfo(committed, message)
269+
270+ def mailinfo(self, files, message = ""):
271+ towhom = "sjoerd@cwi.nl, jack@cwi.nl" # XXX
272+ mailtext = MAILFORM % (towhom, string.join(files),
273+ string.join(files), message)
274+ print '-'*70
275+ print mailtext
276+ print '-'*70
277+ ok = raw_input("OK to mail to %s? " % towhom)
278+ if string.lower(string.strip(ok)) in ('y', 'ye', 'yes'):
279+ p = os.popen(SENDMAIL, "w")
280+ p.write(mailtext)
281+ sts = p.close()
282+ if sts:
283+ print "Sendmail exit status %s" % str(sts)
284+ else:
285+ print "Mail sent."
286+ else:
287+ print "No mail sent."
288+
289+ def report(self, files):
290+ for e in self.whichentries(files):
291+ e.report()
292+
293+ def diff(self, files, opts):
294+ for e in self.whichentries(files):
295+ e.diff(opts)
296+
297+ def add(self, files):
298+ if not files:
299+ raise RuntimeError, "'cvs add' needs at least one file"
300+ list = []
301+ for e in self.whichentries(files, 1):
302+ e.add()
303+
304+ def rm(self, files):
305+ if not files:
306+ raise RuntimeError, "'cvs rm' needs at least one file"
307+ raise RuntimeError, "'cvs rm' not yet imlemented"
308+
309+ def log(self, files, opts):
310+ flags = ''
311+ for o, a in opts:
312+ flags = flags + ' ' + o + a
313+ for e in self.whichentries(files):
314+ e.log(flags)
315+
316+ def whichentries(self, files, localfilestoo = 0):
317+ if files:
318+ list = []
319+ for file in files:
320+ if self.entries.has_key(file):
321+ e = self.entries[file]
322+ else:
323+ e = self.FileClass(file)
324+ self.entries[file] = e
325+ list.append(e)
326+ else:
327+ list = self.entries.values()
328+ for file in self.proxy.listfiles():
329+ if self.entries.has_key(file):
330+ continue
331+ e = self.FileClass(file)
332+ self.entries[file] = e
333+ list.append(e)
334+ if localfilestoo:
335+ for file in os.listdir(os.curdir):
336+ if not self.entries.has_key(file) \
337+ and not self.ignored(file):
338+ e = self.FileClass(file)
339+ self.entries[file] = e
340+ list.append(e)
341+ list.sort()
342+ if self.proxy:
343+ for e in list:
344+ if e.proxy is None:
345+ e.proxy = self.proxy
346+ return list
347+
348+
349+class rcvs(CommandFrameWork):
350+
351+ GlobalFlags = 'd:h:p:qvL'
352+ UsageMessage = \
353+"usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] [subcommand arg ...]"
354+ PostUsageMessage = \
355+ "If no subcommand is given, the status of all files is listed"
356+
357+ def __init__(self):
358+ """Constructor."""
359+ CommandFrameWork.__init__(self)
360+ self.proxy = None
361+ self.cvs = RCVS()
362+
363+ def close(self):
364+ if self.proxy:
365+ self.proxy._close()
366+ self.proxy = None
367+
368+ def recurse(self):
369+ self.close()
370+ names = os.listdir(os.curdir)
371+ for name in names:
372+ if name == os.curdir or name == os.pardir:
373+ continue
374+ if name == "CVS":
375+ continue
376+ if not os.path.isdir(name):
377+ continue
378+ if os.path.islink(name):
379+ continue
380+ print "--- entering subdirectory", name, "---"
381+ os.chdir(name)
382+ try:
383+ if os.path.isdir("CVS"):
384+ self.__class__().run()
385+ else:
386+ self.recurse()
387+ finally:
388+ os.chdir(os.pardir)
389+ print "--- left subdirectory", name, "---"
390+
391+ def options(self, opts):
392+ self.opts = opts
393+
394+ def ready(self):
395+ import rcsclient
396+ self.proxy = rcsclient.openrcsclient(self.opts)
397+ self.cvs.setproxy(self.proxy)
398+ self.cvs.getentries()
399+
400+ def default(self):
401+ self.cvs.report([])
402+
403+ def do_report(self, opts, files):
404+ self.cvs.report(files)
405+
406+ def do_update(self, opts, files):
407+ """update [-l] [-R] [file] ..."""
408+ local = DEF_LOCAL
409+ for o, a in opts:
410+ if o == '-l': local = 1
411+ if o == '-R': local = 0
412+ self.cvs.update(files)
413+ self.cvs.putentries()
414+ if not local and not files:
415+ self.recurse()
416+ flags_update = '-lR'
417+ do_up = do_update
418+ flags_up = flags_update
419+
420+ def do_commit(self, opts, files):
421+ """commit [-m message] [file] ..."""
422+ message = ""
423+ for o, a in opts:
424+ if o == '-m': message = a
425+ self.cvs.commit(files, message)
426+ self.cvs.putentries()
427+ flags_commit = 'm:'
428+ do_com = do_commit
429+ flags_com = flags_commit
430+
431+ def do_diff(self, opts, files):
432+ """diff [difflags] [file] ..."""
433+ self.cvs.diff(files, opts)
434+ flags_diff = 'cbitwcefhnlr:sD:S:'
435+ do_dif = do_diff
436+ flags_dif = flags_diff
437+
438+ def do_add(self, opts, files):
439+ """add file ..."""
440+ if not files:
441+ print "'rcvs add' requires at least one file"
442+ return
443+ self.cvs.add(files)
444+ self.cvs.putentries()
445+
446+ def do_remove(self, opts, files):
447+ """remove file ..."""
448+ if not files:
449+ print "'rcvs remove' requires at least one file"
450+ return
451+ self.cvs.remove(files)
452+ self.cvs.putentries()
453+ do_rm = do_remove
454+
455+ def do_log(self, opts, files):
456+ """log [rlog-options] [file] ..."""
457+ self.cvs.log(files, opts)
458+ flags_log = 'bhLNRtd:s:V:r:'
459+
460+
461+def remove(fn):
462+ try:
463+ os.unlink(fn)
464+ except os.error:
465+ pass
466+
467+
468+def main():
469+ r = rcvs()
470+ try:
471+ r.run()
472+ finally:
473+ r.close()
474+
475+
476+if __name__ == "__main__":
477+ main()
sys/src/cmd/python/Demo/pdist/rrcs+8−0
@@ -0,0 +1,8 @@
1+#!/usr/bin/env python
2+
3+import addpack
4+addpack.addpack('/home/guido/src/python/Demo/pdist')
5+
6+import rrcs
7+
8+rrcs.main()
sys/src/cmd/python/Demo/pdist/rrcs.py+160−0
@@ -0,0 +1,160 @@
1+#! /usr/bin/env python
2+
3+"Remote RCS -- command line interface"
4+
5+import sys
6+import os
7+import getopt
8+import string
9+import md5
10+import tempfile
11+from rcsclient import openrcsclient
12+
13+def main():
14+ sys.stdout = sys.stderr
15+ try:
16+ opts, rest = getopt.getopt(sys.argv[1:], 'h:p:d:qvL')
17+ if not rest:
18+ cmd = 'head'
19+ else:
20+ cmd, rest = rest[0], rest[1:]
21+ if not commands.has_key(cmd):
22+ raise getopt.error, "unknown command"
23+ coptset, func = commands[cmd]
24+ copts, files = getopt.getopt(rest, coptset)
25+ except getopt.error, msg:
26+ print msg
27+ print "usage: rrcs [options] command [options] [file] ..."
28+ print "where command can be:"
29+ print " ci|put # checkin the given files"
30+ print " co|get # checkout"
31+ print " info # print header info"
32+ print " head # print revision of head branch"
33+ print " list # list filename if valid"
34+ print " log # print full log"
35+ print " diff # diff rcs file and work file"
36+ print "if no files are given, all remote rcs files are assumed"
37+ sys.exit(2)
38+ x = openrcsclient(opts)
39+ if not files:
40+ files = x.listfiles()
41+ for fn in files:
42+ try:
43+ func(x, copts, fn)
44+ except (IOError, os.error), msg:
45+ print "%s: %s" % (fn, msg)
46+
47+def checkin(x, copts, fn):
48+ f = open(fn)
49+ data = f.read()
50+ f.close()
51+ new = not x.isvalid(fn)
52+ if not new and same(x, copts, fn, data):
53+ print "%s: unchanged since last checkin" % fn
54+ return
55+ print "Checking in", fn, "..."
56+ message = asklogmessage(new)
57+ messages = x.put(fn, data, message)
58+ if messages:
59+ print messages
60+
61+def checkout(x, copts, fn):
62+ data = x.get(fn)
63+ f = open(fn, 'w')
64+ f.write(data)
65+ f.close()
66+
67+def lock(x, copts, fn):
68+ x.lock(fn)
69+
70+def unlock(x, copts, fn):
71+ x.unlock(fn)
72+
73+def info(x, copts, fn):
74+ dict = x.info(fn)
75+ keys = dict.keys()
76+ keys.sort()
77+ for key in keys:
78+ print key + ':', dict[key]
79+ print '='*70
80+
81+def head(x, copts, fn):
82+ head = x.head(fn)
83+ print fn, head
84+
85+def list(x, copts, fn):
86+ if x.isvalid(fn):
87+ print fn
88+
89+def log(x, copts, fn):
90+ flags = ''
91+ for o, a in copts:
92+ flags = flags + ' ' + o + a
93+ flags = flags[1:]
94+ messages = x.log(fn, flags)
95+ print messages
96+
97+def diff(x, copts, fn):
98+ if same(x, copts, fn):
99+ return
100+ flags = ''
101+ for o, a in copts:
102+ flags = flags + ' ' + o + a
103+ flags = flags[1:]
104+ data = x.get(fn)
105+ tf = tempfile.NamedTemporaryFile()
106+ tf.write(data)
107+ tf.flush()
108+ print 'diff %s -r%s %s' % (flags, x.head(fn), fn)
109+ sts = os.system('diff %s %s %s' % (flags, tf.name, fn))
110+ if sts:
111+ print '='*70
112+
113+def same(x, copts, fn, data = None):
114+ if data is None:
115+ f = open(fn)
116+ data = f.read()
117+ f.close()
118+ lsum = md5.new(data).digest()
119+ rsum = x.sum(fn)
120+ return lsum == rsum
121+
122+def asklogmessage(new):
123+ if new:
124+ print "enter description,",
125+ else:
126+ print "enter log message,",
127+ print "terminate with single '.' or end of file:"
128+ if new:
129+ print "NOTE: This is NOT the log message!"
130+ message = ""
131+ while 1:
132+ sys.stderr.write(">> ")
133+ sys.stderr.flush()
134+ line = sys.stdin.readline()
135+ if not line or line == '.\n': break
136+ message = message + line
137+ return message
138+
139+def remove(fn):
140+ try:
141+ os.unlink(fn)
142+ except os.error:
143+ pass
144+
145+commands = {
146+ 'ci': ('', checkin),
147+ 'put': ('', checkin),
148+ 'co': ('', checkout),
149+ 'get': ('', checkout),
150+ 'info': ('', info),
151+ 'head': ('', head),
152+ 'list': ('', list),
153+ 'lock': ('', lock),
154+ 'unlock': ('', unlock),
155+ 'log': ('bhLRtd:l:r:s:w:V:', log),
156+ 'diff': ('c', diff),
157+ }
158+
159+if __name__ == '__main__':
160+ main()
sys/src/cmd/python/Demo/pdist/security.py+33−0
@@ -0,0 +1,33 @@
1+class Security:
2+
3+ def __init__(self):
4+ import os
5+ env = os.environ
6+ if env.has_key('PYTHON_KEYFILE'):
7+ keyfile = env['PYTHON_KEYFILE']
8+ else:
9+ keyfile = '.python_keyfile'
10+ if env.has_key('HOME'):
11+ keyfile = os.path.join(env['HOME'], keyfile)
12+ if not os.path.exists(keyfile):
13+ import sys
14+ for dir in sys.path:
15+ kf = os.path.join(dir, keyfile)
16+ if os.path.exists(kf):
17+ keyfile = kf
18+ break
19+ try:
20+ self._key = eval(open(keyfile).readline())
21+ except IOError:
22+ raise IOError, "python keyfile %s: cannot open" % keyfile
23+
24+ def _generate_challenge(self):
25+ import random
26+ return random.randint(100, 100000)
27+
28+ def _compare_challenge_response(self, challenge, response):
29+ return self._encode_challenge(challenge) == response
30+
31+ def _encode_challenge(self, challenge):
32+ p, m = self._key
33+ return pow(long(challenge), p, m)
sys/src/cmd/python/Demo/pdist/server.py+145−0
@@ -0,0 +1,145 @@
1+"""RPC Server module."""
2+
3+import sys
4+import socket
5+import pickle
6+from fnmatch import fnmatch
7+from repr import repr
8+
9+
10+# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)
11+VERBOSE = 1
12+
13+
14+class Server:
15+
16+ """RPC Server class. Derive a class to implement a particular service."""
17+
18+ def __init__(self, address, verbose = VERBOSE):
19+ if type(address) == type(0):
20+ address = ('', address)
21+ self._address = address
22+ self._verbose = verbose
23+ self._socket = None
24+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
25+ self._socket.bind(address)
26+ self._socket.listen(1)
27+ self._listening = 1
28+
29+ def _setverbose(self, verbose):
30+ self._verbose = verbose
31+
32+ def __del__(self):
33+ self._close()
34+
35+ def _close(self):
36+ self._listening = 0
37+ if self._socket:
38+ self._socket.close()
39+ self._socket = None
40+
41+ def _serverloop(self):
42+ while self._listening:
43+ self._serve()
44+
45+ def _serve(self):
46+ if self._verbose: print "Wait for connection ..."
47+ conn, address = self._socket.accept()
48+ if self._verbose: print "Accepted connection from %s" % repr(address)
49+ if not self._verify(conn, address):
50+ print "*** Connection from %s refused" % repr(address)
51+ conn.close()
52+ return
53+ rf = conn.makefile('r')
54+ wf = conn.makefile('w')
55+ ok = 1
56+ while ok:
57+ wf.flush()
58+ if self._verbose > 1: print "Wait for next request ..."
59+ ok = self._dorequest(rf, wf)
60+
61+ _valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*']
62+
63+ def _verify(self, conn, address):
64+ host, port = address
65+ for pat in self._valid:
66+ if fnmatch(host, pat): return 1
67+ return 0
68+
69+ def _dorequest(self, rf, wf):
70+ rp = pickle.Unpickler(rf)
71+ try:
72+ request = rp.load()
73+ except EOFError:
74+ return 0
75+ if self._verbose > 1: print "Got request: %s" % repr(request)
76+ try:
77+ methodname, args, id = request
78+ if '.' in methodname:
79+ reply = (None, self._special(methodname, args), id)
80+ elif methodname[0] == '_':
81+ raise NameError, "illegal method name %s" % repr(methodname)
82+ else:
83+ method = getattr(self, methodname)
84+ reply = (None, apply(method, args), id)
85+ except:
86+ reply = (sys.exc_type, sys.exc_value, id)
87+ if id < 0 and reply[:2] == (None, None):
88+ if self._verbose > 1: print "Suppress reply"
89+ return 1
90+ if self._verbose > 1: print "Send reply: %s" % repr(reply)
91+ wp = pickle.Pickler(wf)
92+ wp.dump(reply)
93+ return 1
94+
95+ def _special(self, methodname, args):
96+ if methodname == '.methods':
97+ if not hasattr(self, '_methods'):
98+ self._methods = tuple(self._listmethods())
99+ return self._methods
100+ raise NameError, "unrecognized special method name %s" % repr(methodname)
101+
102+ def _listmethods(self, cl=None):
103+ if not cl: cl = self.__class__
104+ names = cl.__dict__.keys()
105+ names = filter(lambda x: x[0] != '_', names)
106+ names.sort()
107+ for base in cl.__bases__:
108+ basenames = self._listmethods(base)
109+ basenames = filter(lambda x, names=names: x not in names, basenames)
110+ names[len(names):] = basenames
111+ return names
112+
113+
114+from security import Security
115+
116+
117+class SecureServer(Server, Security):
118+
119+ def __init__(self, *args):
120+ apply(Server.__init__, (self,) + args)
121+ Security.__init__(self)
122+
123+ def _verify(self, conn, address):
124+ import string
125+ challenge = self._generate_challenge()
126+ conn.send("%d\n" % challenge)
127+ response = ""
128+ while "\n" not in response and len(response) < 100:
129+ data = conn.recv(100)
130+ if not data:
131+ break
132+ response = response + data
133+ try:
134+ response = string.atol(string.strip(response))
135+ except string.atol_error:
136+ if self._verbose > 0:
137+ print "Invalid response syntax", repr(response)
138+ return 0
139+ if not self._compare_challenge_response(challenge, response):
140+ if self._verbose > 0:
141+ print "Invalid response value", repr(response)
142+ return 0
143+ if self._verbose > 1:
144+ print "Response matches challenge. Go ahead!"
145+ return 1
sys/src/cmd/python/Demo/pdist/sumtree.py+24−0
@@ -0,0 +1,24 @@
1+import time
2+import FSProxy
3+
4+def main():
5+ t1 = time.time()
6+ #proxy = FSProxy.FSProxyClient(('voorn.cwi.nl', 4127))
7+ proxy = FSProxy.FSProxyLocal()
8+ sumtree(proxy)
9+ proxy._close()
10+ t2 = time.time()
11+ print t2-t1, "seconds"
12+ raw_input("[Return to exit] ")
13+
14+def sumtree(proxy):
15+ print "PWD =", proxy.pwd()
16+ files = proxy.listfiles()
17+ proxy.infolist(files)
18+ subdirs = proxy.listsubdirs()
19+ for name in subdirs:
20+ proxy.cd(name)
21+ sumtree(proxy)
22+ proxy.back()
23+
24+main()
sys/src/cmd/python/Demo/pysvr/Makefile+57−0
@@ -0,0 +1,57 @@
1+# Makefile for 'pysvr' application embedding Python.
2+# Tailored for Python 1.5a3 or later.
3+# Some details are specific for Solaris or CNRI.
4+# Also see ## comments for tailoring.
5+
6+# Which C compiler
7+CC=gcc
8+##PURIFY=/usr/local/pure/purify
9+LINKCC=$(PURIFY) $(CC)
10+
11+# Optimization preferences
12+OPT=-g
13+
14+# Which Python version we're using
15+VER=2.2
16+
17+# Expressions using the above definitions
18+PYVER=python$(VER)
19+
20+# Use these defs when compiling against installed Python
21+##INST=/usr/local
22+##PYC=$(INST)/lib/$(PYVER)/config
23+##PYINCL=-I$(INST)/include/$(PYVER) -I$(PYC)
24+##PYLIBS=$(PYC)/lib$(PYVER).a
25+
26+# Use these defs when compiling against built Python
27+PLAT=linux
28+PYINCL=-I../../Include -I../../$(PLAT)
29+PYLIBS=../../$(PLAT)/lib$(PYVER).a
30+
31+# Libraries to link with -- very installation dependent
32+# (See LIBS= in Modules/Makefile in build tree)
33+RLLIBS=-lreadline -ltermcap
34+OTHERLIBS=-lnsl -lpthread -ldl -lm -ldb -lutil
35+
36+# Compilation and link flags -- no need to change normally
37+CFLAGS=$(OPT)
38+CPPFLAGS=$(PYINCL)
39+LIBS=$(PYLIBS) $(RLLIBS) $(OTHERLIBS)
40+
41+# Default port for the pysvr application
42+PORT=4000
43+
44+# Default target
45+all: pysvr
46+
47+# Target to build pysvr
48+pysvr: pysvr.o $(PYOBJS) $(PYLIBS)
49+ $(LINKCC) pysvr.o $(LIBS) -o pysvr
50+
51+# Target to build and run pysvr
52+run: pysvr
53+ pysvr $(PORT)
54+
55+# Target to clean up the directory
56+clean:
57+ -rm -f pysvr *.o *~ core
sys/src/cmd/python/Demo/pysvr/README+9−0
@@ -0,0 +1,9 @@
1+This is an example of a multi-threaded C application embedding a
2+Python interpreter.
3+
4+The particular application is a multi-threaded telnet-like server that
5+provides you with a Python prompt (instead of a shell prompt).
6+
7+The file pysvr.py is a prototype in Python.
8+
9+THIS APPLICATION IS NOT SECURE -- ONLY USE IT FOR TESTING!
sys/src/cmd/python/Demo/pysvr/pysvr.c+370−0
@@ -0,0 +1,370 @@
1+/* A multi-threaded telnet-like server that gives a Python prompt.
2+
3+Usage: pysvr [port]
4+
5+For security reasons, it only accepts requests from the current host.
6+This can still be insecure, but restricts violations from people who
7+can log in on your machine. Use with caution!
8+
9+*/
10+
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <string.h>
14+#include <ctype.h>
15+#include <errno.h>
16+
17+#include <sys/types.h>
18+#include <sys/socket.h>
19+#include <netinet/in.h>
20+
21+#include <pthread.h>
22+#include <getopt.h>
23+
24+/* XXX Umpfh.
25+ Python.h defines a typedef destructor, which conflicts with pthread.h.
26+ So Python.h must be included after pthread.h. */
27+
28+#include "Python.h"
29+
30+extern int Py_VerboseFlag;
31+
32+#ifndef PORT
33+#define PORT 4000
34+#endif
35+
36+struct workorder {
37+ int conn;
38+ struct sockaddr_in addr;
39+};
40+
41+/* Forward */
42+static void init_python(void);
43+static void usage(void);
44+static void oprogname(void);
45+static void main_thread(int);
46+static void create_thread(int, struct sockaddr_in *);
47+static void *service_thread(struct workorder *);
48+static void run_interpreter(FILE *, FILE *);
49+static int run_command(char *, PyObject *);
50+static void ps(void);
51+
52+static char *progname = "pysvr";
53+
54+static PyThreadState *gtstate;
55+
56+main(int argc, char **argv)
57+{
58+ int port = PORT;
59+ int c;
60+
61+ if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
62+ progname = argv[0];
63+
64+ while ((c = getopt(argc, argv, "v")) != EOF) {
65+ switch (c) {
66+ case 'v':
67+ Py_VerboseFlag++;
68+ break;
69+ default:
70+ usage();
71+ }
72+ }
73+
74+ if (optind < argc) {
75+ if (optind+1 < argc) {
76+ oprogname();
77+ fprintf(stderr, "too many arguments\n");
78+ usage();
79+ }
80+ port = atoi(argv[optind]);
81+ if (port <= 0) {
82+ fprintf(stderr, "bad port (%s)\n", argv[optind]);
83+ usage();
84+ }
85+ }
86+
87+ main_thread(port);
88+
89+ fprintf(stderr, "Bye.\n");
90+
91+ exit(0);
92+}
93+
94+static char usage_line[] = "usage: %s [port]\n";
95+
96+static void
97+usage(void)
98+{
99+ fprintf(stderr, usage_line, progname);
100+ exit(2);
101+}
102+
103+static void
104+main_thread(int port)
105+{
106+ int sock, conn, size, i;
107+ struct sockaddr_in addr, clientaddr;
108+
109+ sock = socket(PF_INET, SOCK_STREAM, 0);
110+ if (sock < 0) {
111+ oprogname();
112+ perror("can't create socket");
113+ exit(1);
114+ }
115+
116+#ifdef SO_REUSEADDR
117+ i = 1;
118+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
119+#endif
120+
121+ memset((char *)&addr, '\0', sizeof addr);
122+ addr.sin_family = AF_INET;
123+ addr.sin_port = htons(port);
124+ addr.sin_addr.s_addr = 0L;
125+ if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
126+ oprogname();
127+ perror("can't bind socket to address");
128+ exit(1);
129+ }
130+
131+ if (listen(sock, 5) < 0) {
132+ oprogname();
133+ perror("can't listen on socket");
134+ exit(1);
135+ }
136+
137+ fprintf(stderr, "Listening on port %d...\n", port);
138+
139+ for (i = 0; ; i++) {
140+ size = sizeof clientaddr;
141+ memset((char *) &clientaddr, '\0', size);
142+ conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
143+ if (conn < 0) {
144+ oprogname();
145+ perror("can't accept connection from socket");
146+ exit(1);
147+ }
148+
149+ size = sizeof addr;
150+ memset((char *) &addr, '\0', size);
151+ if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
152+ oprogname();
153+ perror("can't get socket name of connection");
154+ exit(1);
155+ }
156+ if (clientaddr.sin_addr.s_addr != addr.sin_addr.s_addr) {
157+ oprogname();
158+ perror("connection from non-local host refused");
159+ fprintf(stderr, "(addr=%lx, clientaddr=%lx)\n",
160+ ntohl(addr.sin_addr.s_addr),
161+ ntohl(clientaddr.sin_addr.s_addr));
162+ close(conn);
163+ continue;
164+ }
165+ if (i == 4) {
166+ close(conn);
167+ break;
168+ }
169+ create_thread(conn, &clientaddr);
170+ }
171+
172+ close(sock);
173+
174+ if (gtstate) {
175+ PyEval_AcquireThread(gtstate);
176+ gtstate = NULL;
177+ Py_Finalize();
178+ /* And a second time, just because we can. */
179+ Py_Finalize(); /* This should be harmless. */
180+ }
181+ exit(0);
182+}
183+
184+static void
185+create_thread(int conn, struct sockaddr_in *addr)
186+{
187+ struct workorder *work;
188+ pthread_t tdata;
189+
190+ work = malloc(sizeof(struct workorder));
191+ if (work == NULL) {
192+ oprogname();
193+ fprintf(stderr, "out of memory for thread.\n");
194+ close(conn);
195+ return;
196+ }
197+ work->conn = conn;
198+ work->addr = *addr;
199+
200+ init_python();
201+
202+ if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
203+ oprogname();
204+ perror("can't create new thread");
205+ close(conn);
206+ return;
207+ }
208+
209+ if (pthread_detach(tdata) < 0) {
210+ oprogname();
211+ perror("can't detach from thread");
212+ }
213+}
214+
215+static PyThreadState *the_tstate;
216+static PyInterpreterState *the_interp;
217+static PyObject *the_builtins;
218+
219+static void
220+init_python(void)
221+{
222+ if (gtstate)
223+ return;
224+ Py_Initialize(); /* Initialize the interpreter */
225+ PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
226+ gtstate = PyEval_SaveThread(); /* Release the thread state */
227+}
228+
229+static void *
230+service_thread(struct workorder *work)
231+{
232+ FILE *input, *output;
233+
234+ fprintf(stderr, "Start thread for connection %d.\n", work->conn);
235+
236+ ps();
237+
238+ input = fdopen(work->conn, "r");
239+ if (input == NULL) {
240+ oprogname();
241+ perror("can't create input stream");
242+ goto done;
243+ }
244+
245+ output = fdopen(work->conn, "w");
246+ if (output == NULL) {
247+ oprogname();
248+ perror("can't create output stream");
249+ fclose(input);
250+ goto done;
251+ }
252+
253+ setvbuf(input, NULL, _IONBF, 0);
254+ setvbuf(output, NULL, _IONBF, 0);
255+
256+ run_interpreter(input, output);
257+
258+ fclose(input);
259+ fclose(output);
260+
261+ done:
262+ fprintf(stderr, "End thread for connection %d.\n", work->conn);
263+ close(work->conn);
264+ free(work);
265+}
266+
267+static void
268+oprogname(void)
269+{
270+ int save = errno;
271+ fprintf(stderr, "%s: ", progname);
272+ errno = save;
273+}
274+
275+static void
276+run_interpreter(FILE *input, FILE *output)
277+{
278+ PyThreadState *tstate;
279+ PyObject *new_stdin, *new_stdout;
280+ PyObject *mainmod, *globals;
281+ char buffer[1000];
282+ char *p, *q;
283+ int n, end;
284+
285+ PyEval_AcquireLock();
286+ tstate = Py_NewInterpreter();
287+ if (tstate == NULL) {
288+ fprintf(output, "Sorry -- can't create an interpreter\n");
289+ return;
290+ }
291+
292+ mainmod = PyImport_AddModule("__main__");
293+ globals = PyModule_GetDict(mainmod);
294+ Py_INCREF(globals);
295+
296+ new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
297+ new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
298+
299+ PySys_SetObject("stdin", new_stdin);
300+ PySys_SetObject("stdout", new_stdout);
301+ PySys_SetObject("stderr", new_stdout);
302+
303+ for (n = 1; !PyErr_Occurred(); n++) {
304+ Py_BEGIN_ALLOW_THREADS
305+ fprintf(output, "%d> ", n);
306+ p = fgets(buffer, sizeof buffer, input);
307+ Py_END_ALLOW_THREADS
308+
309+ if (p == NULL)
310+ break;
311+ if (p[0] == '\377' && p[1] == '\354')
312+ break;
313+
314+ q = strrchr(p, '\r');
315+ if (q && q[1] == '\n' && q[2] == '\0') {
316+ *q++ = '\n';
317+ *q++ = '\0';
318+ }
319+
320+ while (*p && isspace(*p))
321+ p++;
322+ if (p[0] == '#' || p[0] == '\0')
323+ continue;
324+
325+ end = run_command(buffer, globals);
326+ if (end < 0)
327+ PyErr_Print();
328+
329+ if (end)
330+ break;
331+ }
332+
333+ Py_XDECREF(globals);
334+ Py_XDECREF(new_stdin);
335+ Py_XDECREF(new_stdout);
336+
337+ Py_EndInterpreter(tstate);
338+ PyEval_ReleaseLock();
339+
340+ fprintf(output, "Goodbye!\n");
341+}
342+
343+static int
344+run_command(char *buffer, PyObject *globals)
345+{
346+ PyObject *m, *d, *v;
347+ fprintf(stderr, "run_command: %s", buffer);
348+ if (strchr(buffer, '\n') == NULL)
349+ fprintf(stderr, "\n");
350+ v = PyRun_String(buffer, Py_single_input, globals, globals);
351+ if (v == NULL) {
352+ if (PyErr_Occurred() == PyExc_SystemExit) {
353+ PyErr_Clear();
354+ return 1;
355+ }
356+ PyErr_Print();
357+ return 0;
358+ }
359+ Py_DECREF(v);
360+ return 0;
361+}
362+
363+static void
364+ps(void)
365+{
366+ char buffer[100];
367+ PyOS_snprintf(buffer, sizeof(buffer),
368+ "ps -l -p %d </dev/null | sed 1d\n", getpid());
369+ system(buffer);
370+}
sys/src/cmd/python/Demo/pysvr/pysvr.py+124−0
@@ -0,0 +1,124 @@
1+#! /usr/bin/env python
2+
3+"""A multi-threaded telnet-like server that gives a Python prompt.
4+
5+This is really a prototype for the same thing in C.
6+
7+Usage: pysvr.py [port]
8+
9+For security reasons, it only accepts requests from the current host.
10+This can still be insecure, but restricts violations from people who
11+can log in on your machine. Use with caution!
12+
13+"""
14+
15+import sys, os, string, getopt, thread, socket, traceback
16+
17+PORT = 4000 # Default port
18+
19+def main():
20+ try:
21+ opts, args = getopt.getopt(sys.argv[1:], "")
22+ if len(args) > 1:
23+ raise getopt.error, "Too many arguments."
24+ except getopt.error, msg:
25+ usage(msg)
26+ for o, a in opts:
27+ pass
28+ if args:
29+ try:
30+ port = string.atoi(args[0])
31+ except ValueError, msg:
32+ usage(msg)
33+ else:
34+ port = PORT
35+ main_thread(port)
36+
37+def usage(msg=None):
38+ sys.stdout = sys.stderr
39+ if msg:
40+ print msg
41+ print "\n", __doc__,
42+ sys.exit(2)
43+
44+def main_thread(port):
45+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
46+ sock.bind(("", port))
47+ sock.listen(5)
48+ print "Listening on port", port, "..."
49+ while 1:
50+ (conn, addr) = sock.accept()
51+ if addr[0] != conn.getsockname()[0]:
52+ conn.close()
53+ print "Refusing connection from non-local host", addr[0], "."
54+ continue
55+ thread.start_new_thread(service_thread, (conn, addr))
56+ del conn, addr
57+
58+def service_thread(conn, addr):
59+ (caddr, cport) = addr
60+ print "Thread %s has connection from %s.\n" % (str(thread.get_ident()),
61+ caddr),
62+ stdin = conn.makefile("r")
63+ stdout = conn.makefile("w", 0)
64+ run_interpreter(stdin, stdout)
65+ print "Thread %s is done.\n" % str(thread.get_ident()),
66+
67+def run_interpreter(stdin, stdout):
68+ globals = {}
69+ try:
70+ str(sys.ps1)
71+ except:
72+ sys.ps1 = ">>> "
73+ source = ""
74+ while 1:
75+ stdout.write(sys.ps1)
76+ line = stdin.readline()
77+ if line[:2] == '\377\354':
78+ line = ""
79+ if not line and not source:
80+ break
81+ if line[-2:] == '\r\n':
82+ line = line[:-2] + '\n'
83+ source = source + line
84+ try:
85+ code = compile_command(source)
86+ except SyntaxError, err:
87+ source = ""
88+ traceback.print_exception(SyntaxError, err, None, file=stdout)
89+ continue
90+ if not code:
91+ continue
92+ source = ""
93+ try:
94+ run_command(code, stdin, stdout, globals)
95+ except SystemExit, how:
96+ if how:
97+ try:
98+ how = str(how)
99+ except:
100+ how = ""
101+ stdout.write("Exit %s\n" % how)
102+ break
103+ stdout.write("\nGoodbye.\n")
104+
105+def run_command(code, stdin, stdout, globals):
106+ save = sys.stdin, sys.stdout, sys.stderr
107+ try:
108+ sys.stdout = sys.stderr = stdout
109+ sys.stdin = stdin
110+ try:
111+ exec code in globals
112+ except SystemExit, how:
113+ raise SystemExit, how, sys.exc_info()[2]
114+ except:
115+ type, value, tb = sys.exc_info()
116+ if tb: tb = tb.tb_next
117+ traceback.print_exception(type, value, tb)
118+ del tb
119+ finally:
120+ sys.stdin, sys.stdout, sys.stderr = save
121+
122+from code import compile_command
123+
124+main()
sys/src/cmd/python/Demo/rpc/MANIFEST+10−0
@@ -0,0 +1,10 @@
1+ File Name Archive # Description
2+-----------------------------------------------------------
3+ MANIFEST 1 This shipping list
4+ README 1
5+ T.py 1
6+ mountclient.py 1
7+ nfsclient.py 1
8+ rpc.py 1
9+ test 1
10+ xdr.py 1
sys/src/cmd/python/Demo/rpc/README+31−0
@@ -0,0 +1,31 @@
1+This is a Python interface to Sun RPC, designed and implemented mostly
2+by reading the Internet RFCs about the subject.
3+
4+*** NOTE: xdr.py has evolved into the standard module xdrlib.py ***
5+
6+There are two library modules, xdr.py and rpc.py, and several example
7+clients: mountclient.py, nfsclient.py, and rnusersclient.py,
8+implementing the NFS Mount protocol, (part of) the NFS protocol, and
9+the "rnusers" protocol (used by rusers(1)), respectively. The latter
10+demonstrates the use of broadcast via the Port mapper's CALLIT
11+procedure.
12+
13+There is also a way to create servers in Python.
14+
15+To test the nfs client, run it from the shell with something like this:
16+
17+ python -c 'import nfsclient; nfsclient.test()' [hostname [filesystemname]]
18+
19+When called without a filesystemname, it lists the filesystems at the
20+host; default host is the local machine.
21+
22+Other clients are tested similarly.
23+
24+For hostname, use e.g. wuarchive.wustl.edu or gatekeeper.dec.com (two
25+hosts that are known to export NFS filesystems with little restrictions).
26+
27+There are now two different RPC compilers:
28+
29+1) Wim Lewis rpcgen.py found on http://www.omnigroup.com/~wiml/soft/stale-index.html#python.
30+
31+2) Peter �strands rpcgen.py, which is part of "pynfs" (http://www.cendio.se/~peter/pynfs/).
sys/src/cmd/python/Demo/rpc/T.py+22−0
@@ -0,0 +1,22 @@
1+# Simple interface to report execution times of program fragments.
2+# Call TSTART() to reset the timer, TSTOP(...) to report times.
3+
4+import sys, os, time
5+
6+def TSTART():
7+ global t0, t1
8+ u, s, cu, cs = os.times()
9+ t0 = u+cu, s+cs, time.time()
10+
11+def TSTOP(*label):
12+ global t0, t1
13+ u, s, cu, cs = os.times()
14+ t1 = u+cu, s+cs, time.time()
15+ tt = []
16+ for i in range(3):
17+ tt.append(t1[i] - t0[i])
18+ [u, s, r] = tt
19+ msg = ''
20+ for x in label: msg = msg + (x + ' ')
21+ msg = msg + '%r user, %r sys, %r real\n' % (u, s, r)
22+ sys.stderr.write(msg)
sys/src/cmd/python/Demo/rpc/mountclient.py+202−0
@@ -0,0 +1,202 @@
1+# Mount RPC client -- RFC 1094 (NFS), Appendix A
2+
3+# This module demonstrates how to write your own RPC client in Python.
4+# When this example was written, there was no RPC compiler for
5+# Python. Without such a compiler, you must first create classes
6+# derived from Packer and Unpacker to handle the data types for the
7+# server you want to interface to. You then write the client class.
8+# If you want to support both the TCP and the UDP version of a
9+# protocol, use multiple inheritance as shown below.
10+
11+
12+import rpc
13+from rpc import Packer, Unpacker, TCPClient, UDPClient
14+
15+
16+# Program number and version for the mount protocol
17+MOUNTPROG = 100005
18+MOUNTVERS = 1
19+
20+# Size of the 'fhandle' opaque structure
21+FHSIZE = 32
22+
23+
24+# Packer derived class for Mount protocol clients.
25+# The only thing we need to pack beyond basic types is an 'fhandle'
26+
27+class MountPacker(Packer):
28+
29+ def pack_fhandle(self, fhandle):
30+ self.pack_fopaque(FHSIZE, fhandle)
31+
32+
33+# Unpacker derived class for Mount protocol clients.
34+# The important types we need to unpack are fhandle, fhstatus,
35+# mountlist and exportlist; mountstruct, exportstruct and groups are
36+# used to unpack components of mountlist and exportlist and the
37+# corresponding functions are passed as function argument to the
38+# generic unpack_list function.
39+
40+class MountUnpacker(Unpacker):
41+
42+ def unpack_fhandle(self):
43+ return self.unpack_fopaque(FHSIZE)
44+
45+ def unpack_fhstatus(self):
46+ status = self.unpack_uint()
47+ if status == 0:
48+ fh = self.unpack_fhandle()
49+ else:
50+ fh = None
51+ return status, fh
52+
53+ def unpack_mountlist(self):
54+ return self.unpack_list(self.unpack_mountstruct)
55+
56+ def unpack_mountstruct(self):
57+ hostname = self.unpack_string()
58+ directory = self.unpack_string()
59+ return (hostname, directory)
60+
61+ def unpack_exportlist(self):
62+ return self.unpack_list(self.unpack_exportstruct)
63+
64+ def unpack_exportstruct(self):
65+ filesys = self.unpack_string()
66+ groups = self.unpack_groups()
67+ return (filesys, groups)
68+
69+ def unpack_groups(self):
70+ return self.unpack_list(self.unpack_string)
71+
72+
73+# These are the procedures specific to the Mount client class.
74+# Think of this as a derived class of either TCPClient or UDPClient.
75+
76+class PartialMountClient:
77+
78+ # This method is called by Client.__init__ to initialize
79+ # self.packer and self.unpacker
80+ def addpackers(self):
81+ self.packer = MountPacker()
82+ self.unpacker = MountUnpacker('')
83+
84+ # This method is called by Client.__init__ to bind the socket
85+ # to a particular network interface and port. We use the
86+ # default network interface, but if we're running as root,
87+ # we want to bind to a reserved port
88+ def bindsocket(self):
89+ import os
90+ try:
91+ uid = os.getuid()
92+ except AttributeError:
93+ uid = 1
94+ if uid == 0:
95+ port = rpc.bindresvport(self.sock, '')
96+ # 'port' is not used
97+ else:
98+ self.sock.bind(('', 0))
99+
100+ # This function is called to cough up a suitable
101+ # authentication object for a call to procedure 'proc'.
102+ def mkcred(self):
103+ if self.cred == None:
104+ self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default()
105+ return self.cred
106+
107+ # The methods Mnt, Dump etc. each implement one Remote
108+ # Procedure Call. This is done by calling self.make_call()
109+ # with as arguments:
110+ #
111+ # - the procedure number
112+ # - the arguments (or None)
113+ # - the "packer" function for the arguments (or None)
114+ # - the "unpacker" function for the return value (or None)
115+ #
116+ # The packer and unpacker function, if not None, *must* be
117+ # methods of self.packer and self.unpacker, respectively.
118+ # A value of None means that there are no arguments or is no
119+ # return value, respectively.
120+ #
121+ # The return value from make_call() is the return value from
122+ # the remote procedure call, as unpacked by the "unpacker"
123+ # function, or None if the unpacker function is None.
124+ #
125+ # (Even if you expect a result of None, you should still
126+ # return the return value from make_call(), since this may be
127+ # needed by a broadcasting version of the class.)
128+ #
129+ # If the call fails, make_call() raises an exception
130+ # (this includes time-outs and invalid results).
131+ #
132+ # Note that (at least with the UDP protocol) there is no
133+ # guarantee that a call is executed at most once. When you do
134+ # get a reply, you know it has been executed at least once;
135+ # when you don't get a reply, you know nothing.
136+
137+ def Mnt(self, directory):
138+ return self.make_call(1, directory, \
139+ self.packer.pack_string, \
140+ self.unpacker.unpack_fhstatus)
141+
142+ def Dump(self):
143+ return self.make_call(2, None, \
144+ None, self.unpacker.unpack_mountlist)
145+
146+ def Umnt(self, directory):
147+ return self.make_call(3, directory, \
148+ self.packer.pack_string, None)
149+
150+ def Umntall(self):
151+ return self.make_call(4, None, None, None)
152+
153+ def Export(self):
154+ return self.make_call(5, None, \
155+ None, self.unpacker.unpack_exportlist)
156+
157+
158+# We turn the partial Mount client into a full one for either protocol
159+# by use of multiple inheritance. (In general, when class C has base
160+# classes B1...Bn, if x is an instance of class C, methods of x are
161+# searched first in C, then in B1, then in B2, ..., finally in Bn.)
162+
163+class TCPMountClient(PartialMountClient, TCPClient):
164+
165+ def __init__(self, host):
166+ TCPClient.__init__(self, host, MOUNTPROG, MOUNTVERS)
167+
168+
169+class UDPMountClient(PartialMountClient, UDPClient):
170+
171+ def __init__(self, host):
172+ UDPClient.__init__(self, host, MOUNTPROG, MOUNTVERS)
173+
174+
175+# A little test program for the Mount client. This takes a host as
176+# command line argument (default the local machine), prints its export
177+# list, and attempts to mount and unmount each exported files system.
178+# An optional first argument of -t or -u specifies the protocol to use
179+# (TCP or UDP), default is UDP.
180+
181+def test():
182+ import sys
183+ if sys.argv[1:] and sys.argv[1] == '-t':
184+ C = TCPMountClient
185+ del sys.argv[1]
186+ elif sys.argv[1:] and sys.argv[1] == '-u':
187+ C = UDPMountClient
188+ del sys.argv[1]
189+ else:
190+ C = UDPMountClient
191+ if sys.argv[1:]: host = sys.argv[1]
192+ else: host = ''
193+ mcl = C(host)
194+ list = mcl.Export()
195+ for item in list:
196+ print item
197+ try:
198+ mcl.Mnt(item[0])
199+ except:
200+ print 'Sorry'
201+ continue
202+ mcl.Umnt(item[0])
sys/src/cmd/python/Demo/rpc/nfsclient.py+201−0
@@ -0,0 +1,201 @@
1+# NFS RPC client -- RFC 1094
2+
3+# XXX This is not yet complete.
4+# XXX Only GETATTR, SETTTR, LOOKUP and READDIR are supported.
5+
6+# (See mountclient.py for some hints on how to write RPC clients in
7+# Python in general)
8+
9+import rpc
10+from rpc import UDPClient, TCPClient
11+from mountclient import FHSIZE, MountPacker, MountUnpacker
12+
13+NFS_PROGRAM = 100003
14+NFS_VERSION = 2
15+
16+# enum stat
17+NFS_OK = 0
18+# (...many error values...)
19+
20+# enum ftype
21+NFNON = 0
22+NFREG = 1
23+NFDIR = 2
24+NFBLK = 3
25+NFCHR = 4
26+NFLNK = 5
27+
28+
29+class NFSPacker(MountPacker):
30+
31+ def pack_sattrargs(self, sa):
32+ file, attributes = sa
33+ self.pack_fhandle(file)
34+ self.pack_sattr(attributes)
35+
36+ def pack_sattr(self, sa):
37+ mode, uid, gid, size, atime, mtime = sa
38+ self.pack_uint(mode)
39+ self.pack_uint(uid)
40+ self.pack_uint(gid)
41+ self.pack_uint(size)
42+ self.pack_timeval(atime)
43+ self.pack_timeval(mtime)
44+
45+ def pack_diropargs(self, da):
46+ dir, name = da
47+ self.pack_fhandle(dir)
48+ self.pack_string(name)
49+
50+ def pack_readdirargs(self, ra):
51+ dir, cookie, count = ra
52+ self.pack_fhandle(dir)
53+ self.pack_uint(cookie)
54+ self.pack_uint(count)
55+
56+ def pack_timeval(self, tv):
57+ secs, usecs = tv
58+ self.pack_uint(secs)
59+ self.pack_uint(usecs)
60+
61+
62+class NFSUnpacker(MountUnpacker):
63+
64+ def unpack_readdirres(self):
65+ status = self.unpack_enum()
66+ if status == NFS_OK:
67+ entries = self.unpack_list(self.unpack_entry)
68+ eof = self.unpack_bool()
69+ rest = (entries, eof)
70+ else:
71+ rest = None
72+ return (status, rest)
73+
74+ def unpack_entry(self):
75+ fileid = self.unpack_uint()
76+ name = self.unpack_string()
77+ cookie = self.unpack_uint()
78+ return (fileid, name, cookie)
79+
80+ def unpack_diropres(self):
81+ status = self.unpack_enum()
82+ if status == NFS_OK:
83+ fh = self.unpack_fhandle()
84+ fa = self.unpack_fattr()
85+ rest = (fh, fa)
86+ else:
87+ rest = None
88+ return (status, rest)
89+
90+ def unpack_attrstat(self):
91+ status = self.unpack_enum()
92+ if status == NFS_OK:
93+ attributes = self.unpack_fattr()
94+ else:
95+ attributes = None
96+ return status, attributes
97+
98+ def unpack_fattr(self):
99+ type = self.unpack_enum()
100+ mode = self.unpack_uint()
101+ nlink = self.unpack_uint()
102+ uid = self.unpack_uint()
103+ gid = self.unpack_uint()
104+ size = self.unpack_uint()
105+ blocksize = self.unpack_uint()
106+ rdev = self.unpack_uint()
107+ blocks = self.unpack_uint()
108+ fsid = self.unpack_uint()
109+ fileid = self.unpack_uint()
110+ atime = self.unpack_timeval()
111+ mtime = self.unpack_timeval()
112+ ctime = self.unpack_timeval()
113+ return (type, mode, nlink, uid, gid, size, blocksize, \
114+ rdev, blocks, fsid, fileid, atime, mtime, ctime)
115+
116+ def unpack_timeval(self):
117+ secs = self.unpack_uint()
118+ usecs = self.unpack_uint()
119+ return (secs, usecs)
120+
121+
122+class NFSClient(UDPClient):
123+
124+ def __init__(self, host):
125+ UDPClient.__init__(self, host, NFS_PROGRAM, NFS_VERSION)
126+
127+ def addpackers(self):
128+ self.packer = NFSPacker()
129+ self.unpacker = NFSUnpacker('')
130+
131+ def mkcred(self):
132+ if self.cred == None:
133+ self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default()
134+ return self.cred
135+
136+ def Getattr(self, fh):
137+ return self.make_call(1, fh, \
138+ self.packer.pack_fhandle, \
139+ self.unpacker.unpack_attrstat)
140+
141+ def Setattr(self, sa):
142+ return self.make_call(2, sa, \
143+ self.packer.pack_sattrargs, \
144+ self.unpacker.unpack_attrstat)
145+
146+ # Root() is obsolete
147+
148+ def Lookup(self, da):
149+ return self.make_call(4, da, \
150+ self.packer.pack_diropargs, \
151+ self.unpacker.unpack_diropres)
152+
153+ # ...
154+
155+ def Readdir(self, ra):
156+ return self.make_call(16, ra, \
157+ self.packer.pack_readdirargs, \
158+ self.unpacker.unpack_readdirres)
159+
160+ # Shorthand to get the entire contents of a directory
161+ def Listdir(self, dir):
162+ list = []
163+ ra = (dir, 0, 2000)
164+ while 1:
165+ (status, rest) = self.Readdir(ra)
166+ if status <> NFS_OK:
167+ break
168+ entries, eof = rest
169+ last_cookie = None
170+ for fileid, name, cookie in entries:
171+ list.append((fileid, name))
172+ last_cookie = cookie
173+ if eof or last_cookie == None:
174+ break
175+ ra = (ra[0], last_cookie, ra[2])
176+ return list
177+
178+
179+def test():
180+ import sys
181+ if sys.argv[1:]: host = sys.argv[1]
182+ else: host = ''
183+ if sys.argv[2:]: filesys = sys.argv[2]
184+ else: filesys = None
185+ from mountclient import UDPMountClient, TCPMountClient
186+ mcl = TCPMountClient(host)
187+ if filesys == None:
188+ list = mcl.Export()
189+ for item in list:
190+ print item
191+ return
192+ sf = mcl.Mnt(filesys)
193+ print sf
194+ fh = sf[1]
195+ if fh:
196+ ncl = NFSClient(host)
197+ as = ncl.Getattr(fh)
198+ print as
199+ list = ncl.Listdir(fh)
200+ for item in list: print item
201+ mcl.Umnt(filesys)
sys/src/cmd/python/Demo/rpc/rnusersclient.py+98−0
@@ -0,0 +1,98 @@
1+# Remote nusers client interface
2+
3+import rpc
4+from rpc import Packer, Unpacker, UDPClient, BroadcastUDPClient
5+
6+
7+class RnusersPacker(Packer):
8+ def pack_utmp(self, ui):
9+ ut_line, ut_name, ut_host, ut_time = utmp
10+ self.pack_string(ut_line)
11+ self.pack_string(ut_name)
12+ self.pack_string(ut_host)
13+ self.pack_int(ut_time)
14+ def pack_utmpidle(self, ui):
15+ ui_itmp, ui_idle = ui
16+ self.pack_utmp(ui_utmp)
17+ self.pack_uint(ui_idle)
18+ def pack_utmpidlearr(self, list):
19+ self.pack_array(list, self.pack_itmpidle)
20+
21+
22+class RnusersUnpacker(Unpacker):
23+ def unpack_utmp(self):
24+ ut_line = self.unpack_string()
25+ ut_name = self.unpack_string()
26+ ut_host = self.unpack_string()
27+ ut_time = self.unpack_int()
28+ return ut_line, ut_name, ut_host, ut_time
29+ def unpack_utmpidle(self):
30+ ui_utmp = self.unpack_utmp()
31+ ui_idle = self.unpack_uint()
32+ return ui_utmp, ui_idle
33+ def unpack_utmpidlearr(self):
34+ return self.unpack_array(self.unpack_utmpidle)
35+
36+
37+class PartialRnusersClient:
38+
39+ def addpackers(self):
40+ self.packer = RnusersPacker()
41+ self.unpacker = RnusersUnpacker('')
42+
43+ def Num(self):
44+ return self.make_call(1, None, None, self.unpacker.unpack_int)
45+
46+ def Names(self):
47+ return self.make_call(2, None, \
48+ None, self.unpacker.unpack_utmpidlearr)
49+
50+ def Allnames(self):
51+ return self.make_call(3, None, \
52+ None, self.unpacker.unpack_utmpidlearr)
53+
54+
55+class RnusersClient(PartialRnusersClient, UDPClient):
56+
57+ def __init__(self, host):
58+ UDPClient.__init__(self, host, 100002, 2)
59+
60+
61+class BroadcastRnusersClient(PartialRnusersClient, BroadcastUDPClient):
62+
63+ def __init__(self, bcastaddr):
64+ BroadcastUDPClient.__init__(self, bcastaddr, 100002, 2)
65+
66+
67+def test():
68+ import sys
69+ if not sys.argv[1:]:
70+ testbcast()
71+ return
72+ else:
73+ host = sys.argv[1]
74+ c = RnusersClient(host)
75+ list = c.Names()
76+ for (line, name, host, time), idle in list:
77+ line = strip0(line)
78+ name = strip0(name)
79+ host = strip0(host)
80+ print "%r %r %r %s %s" % (name, host, line, time, idle)
81+
82+def testbcast():
83+ c = BroadcastRnusersClient('<broadcast>')
84+ def listit(list, fromaddr):
85+ host, port = fromaddr
86+ print host + '\t:',
87+ for (line, name, host, time), idle in list:
88+ print strip0(name),
89+ print
90+ c.set_reply_handler(listit)
91+ all = c.Names()
92+ print 'Total Count:', len(all)
93+
94+def strip0(s):
95+ while s and s[-1] == '\0': s = s[:-1]
96+ return s
97+
98+test()
sys/src/cmd/python/Demo/rpc/rpc.py+893−0
@@ -0,0 +1,893 @@
1+# Sun RPC version 2 -- RFC1057.
2+
3+# XXX There should be separate exceptions for the various reasons why
4+# XXX an RPC can fail, rather than using RuntimeError for everything
5+
6+# XXX Need to use class based exceptions rather than string exceptions
7+
8+# XXX The UDP version of the protocol resends requests when it does
9+# XXX not receive a timely reply -- use only for idempotent calls!
10+
11+# XXX There is no provision for call timeout on TCP connections
12+
13+import xdr
14+import socket
15+import os
16+
17+RPCVERSION = 2
18+
19+CALL = 0
20+REPLY = 1
21+
22+AUTH_NULL = 0
23+AUTH_UNIX = 1
24+AUTH_SHORT = 2
25+AUTH_DES = 3
26+
27+MSG_ACCEPTED = 0
28+MSG_DENIED = 1
29+
30+SUCCESS = 0 # RPC executed successfully
31+PROG_UNAVAIL = 1 # remote hasn't exported program
32+PROG_MISMATCH = 2 # remote can't support version #
33+PROC_UNAVAIL = 3 # program can't support procedure
34+GARBAGE_ARGS = 4 # procedure can't decode params
35+
36+RPC_MISMATCH = 0 # RPC version number != 2
37+AUTH_ERROR = 1 # remote can't authenticate caller
38+
39+AUTH_BADCRED = 1 # bad credentials (seal broken)
40+AUTH_REJECTEDCRED = 2 # client must begin new session
41+AUTH_BADVERF = 3 # bad verifier (seal broken)
42+AUTH_REJECTEDVERF = 4 # verifier expired or replayed
43+AUTH_TOOWEAK = 5 # rejected for security reasons
44+
45+
46+class Packer(xdr.Packer):
47+
48+ def pack_auth(self, auth):
49+ flavor, stuff = auth
50+ self.pack_enum(flavor)
51+ self.pack_opaque(stuff)
52+
53+ def pack_auth_unix(self, stamp, machinename, uid, gid, gids):
54+ self.pack_uint(stamp)
55+ self.pack_string(machinename)
56+ self.pack_uint(uid)
57+ self.pack_uint(gid)
58+ self.pack_uint(len(gids))
59+ for i in gids:
60+ self.pack_uint(i)
61+
62+ def pack_callheader(self, xid, prog, vers, proc, cred, verf):
63+ self.pack_uint(xid)
64+ self.pack_enum(CALL)
65+ self.pack_uint(RPCVERSION)
66+ self.pack_uint(prog)
67+ self.pack_uint(vers)
68+ self.pack_uint(proc)
69+ self.pack_auth(cred)
70+ self.pack_auth(verf)
71+ # Caller must add procedure-specific part of call
72+
73+ def pack_replyheader(self, xid, verf):
74+ self.pack_uint(xid)
75+ self.pack_enum(REPLY)
76+ self.pack_uint(MSG_ACCEPTED)
77+ self.pack_auth(verf)
78+ self.pack_enum(SUCCESS)
79+ # Caller must add procedure-specific part of reply
80+
81+
82+# Exceptions
83+BadRPCFormat = 'rpc.BadRPCFormat'
84+BadRPCVersion = 'rpc.BadRPCVersion'
85+GarbageArgs = 'rpc.GarbageArgs'
86+
87+class Unpacker(xdr.Unpacker):
88+
89+ def unpack_auth(self):
90+ flavor = self.unpack_enum()
91+ stuff = self.unpack_opaque()
92+ return (flavor, stuff)
93+
94+ def unpack_callheader(self):
95+ xid = self.unpack_uint()
96+ temp = self.unpack_enum()
97+ if temp != CALL:
98+ raise BadRPCFormat, 'no CALL but %r' % (temp,)
99+ temp = self.unpack_uint()
100+ if temp != RPCVERSION:
101+ raise BadRPCVersion, 'bad RPC version %r' % (temp,)
102+ prog = self.unpack_uint()
103+ vers = self.unpack_uint()
104+ proc = self.unpack_uint()
105+ cred = self.unpack_auth()
106+ verf = self.unpack_auth()
107+ return xid, prog, vers, proc, cred, verf
108+ # Caller must add procedure-specific part of call
109+
110+ def unpack_replyheader(self):
111+ xid = self.unpack_uint()
112+ mtype = self.unpack_enum()
113+ if mtype != REPLY:
114+ raise RuntimeError, 'no REPLY but %r' % (mtype,)
115+ stat = self.unpack_enum()
116+ if stat == MSG_DENIED:
117+ stat = self.unpack_enum()
118+ if stat == RPC_MISMATCH:
119+ low = self.unpack_uint()
120+ high = self.unpack_uint()
121+ raise RuntimeError, \
122+ 'MSG_DENIED: RPC_MISMATCH: %r' % ((low, high),)
123+ if stat == AUTH_ERROR:
124+ stat = self.unpack_uint()
125+ raise RuntimeError, \
126+ 'MSG_DENIED: AUTH_ERROR: %r' % (stat,)
127+ raise RuntimeError, 'MSG_DENIED: %r' % (stat,)
128+ if stat != MSG_ACCEPTED:
129+ raise RuntimeError, \
130+ 'Neither MSG_DENIED nor MSG_ACCEPTED: %r' % (stat,)
131+ verf = self.unpack_auth()
132+ stat = self.unpack_enum()
133+ if stat == PROG_UNAVAIL:
134+ raise RuntimeError, 'call failed: PROG_UNAVAIL'
135+ if stat == PROG_MISMATCH:
136+ low = self.unpack_uint()
137+ high = self.unpack_uint()
138+ raise RuntimeError, \
139+ 'call failed: PROG_MISMATCH: %r' % ((low, high),)
140+ if stat == PROC_UNAVAIL:
141+ raise RuntimeError, 'call failed: PROC_UNAVAIL'
142+ if stat == GARBAGE_ARGS:
143+ raise RuntimeError, 'call failed: GARBAGE_ARGS'
144+ if stat != SUCCESS:
145+ raise RuntimeError, 'call failed: %r' % (stat,)
146+ return xid, verf
147+ # Caller must get procedure-specific part of reply
148+
149+
150+# Subroutines to create opaque authentication objects
151+
152+def make_auth_null():
153+ return ''
154+
155+def make_auth_unix(seed, host, uid, gid, groups):
156+ p = Packer()
157+ p.pack_auth_unix(seed, host, uid, gid, groups)
158+ return p.get_buf()
159+
160+def make_auth_unix_default():
161+ try:
162+ from os import getuid, getgid
163+ uid = getuid()
164+ gid = getgid()
165+ except ImportError:
166+ uid = gid = 0
167+ import time
168+ return make_auth_unix(int(time.time()-unix_epoch()), \
169+ socket.gethostname(), uid, gid, [])
170+
171+_unix_epoch = -1
172+def unix_epoch():
173+ """Very painful calculation of when the Unix Epoch is.
174+
175+ This is defined as the return value of time.time() on Jan 1st,
176+ 1970, 00:00:00 GMT.
177+
178+ On a Unix system, this should always return 0.0. On a Mac, the
179+ calculations are needed -- and hard because of integer overflow
180+ and other limitations.
181+
182+ """
183+ global _unix_epoch
184+ if _unix_epoch >= 0: return _unix_epoch
185+ import time
186+ now = time.time()
187+ localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...)
188+ gmt = time.gmtime(now)
189+ offset = time.mktime(localt) - time.mktime(gmt)
190+ y, m, d, hh, mm, ss = 1970, 1, 1, 0, 0, 0
191+ offset, ss = divmod(ss + offset, 60)
192+ offset, mm = divmod(mm + offset, 60)
193+ offset, hh = divmod(hh + offset, 24)
194+ d = d + offset
195+ _unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0))
196+ print "Unix epoch:", time.ctime(_unix_epoch)
197+ return _unix_epoch
198+
199+
200+# Common base class for clients
201+
202+class Client:
203+
204+ def __init__(self, host, prog, vers, port):
205+ self.host = host
206+ self.prog = prog
207+ self.vers = vers
208+ self.port = port
209+ self.makesocket() # Assigns to self.sock
210+ self.bindsocket()
211+ self.connsocket()
212+ self.lastxid = 0 # XXX should be more random?
213+ self.addpackers()
214+ self.cred = None
215+ self.verf = None
216+
217+ def close(self):
218+ self.sock.close()
219+
220+ def makesocket(self):
221+ # This MUST be overridden
222+ raise RuntimeError, 'makesocket not defined'
223+
224+ def connsocket(self):
225+ # Override this if you don't want/need a connection
226+ self.sock.connect((self.host, self.port))
227+
228+ def bindsocket(self):
229+ # Override this to bind to a different port (e.g. reserved)
230+ self.sock.bind(('', 0))
231+
232+ def addpackers(self):
233+ # Override this to use derived classes from Packer/Unpacker
234+ self.packer = Packer()
235+ self.unpacker = Unpacker('')
236+
237+ def make_call(self, proc, args, pack_func, unpack_func):
238+ # Don't normally override this (but see Broadcast)
239+ if pack_func is None and args is not None:
240+ raise TypeError, 'non-null args with null pack_func'
241+ self.start_call(proc)
242+ if pack_func:
243+ pack_func(args)
244+ self.do_call()
245+ if unpack_func:
246+ result = unpack_func()
247+ else:
248+ result = None
249+ self.unpacker.done()
250+ return result
251+
252+ def start_call(self, proc):
253+ # Don't override this
254+ self.lastxid = xid = self.lastxid + 1
255+ cred = self.mkcred()
256+ verf = self.mkverf()
257+ p = self.packer
258+ p.reset()
259+ p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
260+
261+ def do_call(self):
262+ # This MUST be overridden
263+ raise RuntimeError, 'do_call not defined'
264+
265+ def mkcred(self):
266+ # Override this to use more powerful credentials
267+ if self.cred == None:
268+ self.cred = (AUTH_NULL, make_auth_null())
269+ return self.cred
270+
271+ def mkverf(self):
272+ # Override this to use a more powerful verifier
273+ if self.verf == None:
274+ self.verf = (AUTH_NULL, make_auth_null())
275+ return self.verf
276+
277+ def call_0(self): # Procedure 0 is always like this
278+ return self.make_call(0, None, None, None)
279+
280+
281+# Record-Marking standard support
282+
283+def sendfrag(sock, last, frag):
284+ x = len(frag)
285+ if last: x = x | 0x80000000L
286+ header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
287+ chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
288+ sock.send(header + frag)
289+
290+def sendrecord(sock, record):
291+ sendfrag(sock, 1, record)
292+
293+def recvfrag(sock):
294+ header = sock.recv(4)
295+ if len(header) < 4:
296+ raise EOFError
297+ x = long(ord(header[0]))<<24 | ord(header[1])<<16 | \
298+ ord(header[2])<<8 | ord(header[3])
299+ last = ((x & 0x80000000) != 0)
300+ n = int(x & 0x7fffffff)
301+ frag = ''
302+ while n > 0:
303+ buf = sock.recv(n)
304+ if not buf: raise EOFError
305+ n = n - len(buf)
306+ frag = frag + buf
307+ return last, frag
308+
309+def recvrecord(sock):
310+ record = ''
311+ last = 0
312+ while not last:
313+ last, frag = recvfrag(sock)
314+ record = record + frag
315+ return record
316+
317+
318+# Try to bind to a reserved port (must be root)
319+
320+last_resv_port_tried = None
321+def bindresvport(sock, host):
322+ global last_resv_port_tried
323+ FIRST, LAST = 600, 1024 # Range of ports to try
324+ if last_resv_port_tried == None:
325+ import os
326+ last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
327+ for i in range(last_resv_port_tried, LAST) + \
328+ range(FIRST, last_resv_port_tried):
329+ last_resv_port_tried = i
330+ try:
331+ sock.bind((host, i))
332+ return last_resv_port_tried
333+ except socket.error, (errno, msg):
334+ if errno != 114:
335+ raise socket.error, (errno, msg)
336+ raise RuntimeError, 'can\'t assign reserved port'
337+
338+
339+# Client using TCP to a specific port
340+
341+class RawTCPClient(Client):
342+
343+ def makesocket(self):
344+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
345+
346+ def do_call(self):
347+ call = self.packer.get_buf()
348+ sendrecord(self.sock, call)
349+ reply = recvrecord(self.sock)
350+ u = self.unpacker
351+ u.reset(reply)
352+ xid, verf = u.unpack_replyheader()
353+ if xid != self.lastxid:
354+ # Can't really happen since this is TCP...
355+ raise RuntimeError, 'wrong xid in reply %r instead of %r' % (
356+ xid, self.lastxid)
357+
358+
359+# Client using UDP to a specific port
360+
361+class RawUDPClient(Client):
362+
363+ def makesocket(self):
364+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
365+
366+ def do_call(self):
367+ call = self.packer.get_buf()
368+ self.sock.send(call)
369+ try:
370+ from select import select
371+ except ImportError:
372+ print 'WARNING: select not found, RPC may hang'
373+ select = None
374+ BUFSIZE = 8192 # Max UDP buffer size
375+ timeout = 1
376+ count = 5
377+ while 1:
378+ r, w, x = [self.sock], [], []
379+ if select:
380+ r, w, x = select(r, w, x, timeout)
381+ if self.sock not in r:
382+ count = count - 1
383+ if count < 0: raise RuntimeError, 'timeout'
384+ if timeout < 25: timeout = timeout *2
385+## print 'RESEND', timeout, count
386+ self.sock.send(call)
387+ continue
388+ reply = self.sock.recv(BUFSIZE)
389+ u = self.unpacker
390+ u.reset(reply)
391+ xid, verf = u.unpack_replyheader()
392+ if xid != self.lastxid:
393+## print 'BAD xid'
394+ continue
395+ break
396+
397+
398+# Client using UDP broadcast to a specific port
399+
400+class RawBroadcastUDPClient(RawUDPClient):
401+
402+ def __init__(self, bcastaddr, prog, vers, port):
403+ RawUDPClient.__init__(self, bcastaddr, prog, vers, port)
404+ self.reply_handler = None
405+ self.timeout = 30
406+
407+ def connsocket(self):
408+ # Don't connect -- use sendto
409+ self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
410+
411+ def set_reply_handler(self, reply_handler):
412+ self.reply_handler = reply_handler
413+
414+ def set_timeout(self, timeout):
415+ self.timeout = timeout # Use None for infinite timeout
416+
417+ def make_call(self, proc, args, pack_func, unpack_func):
418+ if pack_func is None and args is not None:
419+ raise TypeError, 'non-null args with null pack_func'
420+ self.start_call(proc)
421+ if pack_func:
422+ pack_func(args)
423+ call = self.packer.get_buf()
424+ self.sock.sendto(call, (self.host, self.port))
425+ try:
426+ from select import select
427+ except ImportError:
428+ print 'WARNING: select not found, broadcast will hang'
429+ select = None
430+ BUFSIZE = 8192 # Max UDP buffer size (for reply)
431+ replies = []
432+ if unpack_func is None:
433+ def dummy(): pass
434+ unpack_func = dummy
435+ while 1:
436+ r, w, x = [self.sock], [], []
437+ if select:
438+ if self.timeout is None:
439+ r, w, x = select(r, w, x)
440+ else:
441+ r, w, x = select(r, w, x, self.timeout)
442+ if self.sock not in r:
443+ break
444+ reply, fromaddr = self.sock.recvfrom(BUFSIZE)
445+ u = self.unpacker
446+ u.reset(reply)
447+ xid, verf = u.unpack_replyheader()
448+ if xid != self.lastxid:
449+## print 'BAD xid'
450+ continue
451+ reply = unpack_func()
452+ self.unpacker.done()
453+ replies.append((reply, fromaddr))
454+ if self.reply_handler:
455+ self.reply_handler(reply, fromaddr)
456+ return replies
457+
458+
459+# Port mapper interface
460+
461+# Program number, version and (fixed!) port number
462+PMAP_PROG = 100000
463+PMAP_VERS = 2
464+PMAP_PORT = 111
465+
466+# Procedure numbers
467+PMAPPROC_NULL = 0 # (void) -> void
468+PMAPPROC_SET = 1 # (mapping) -> bool
469+PMAPPROC_UNSET = 2 # (mapping) -> bool
470+PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int
471+PMAPPROC_DUMP = 4 # (void) -> pmaplist
472+PMAPPROC_CALLIT = 5 # (call_args) -> call_result
473+
474+# A mapping is (prog, vers, prot, port) and prot is one of:
475+
476+IPPROTO_TCP = 6
477+IPPROTO_UDP = 17
478+
479+# A pmaplist is a variable-length list of mappings, as follows:
480+# either (1, mapping, pmaplist) or (0).
481+
482+# A call_args is (prog, vers, proc, args) where args is opaque;
483+# a call_result is (port, res) where res is opaque.
484+
485+
486+class PortMapperPacker(Packer):
487+
488+ def pack_mapping(self, mapping):
489+ prog, vers, prot, port = mapping
490+ self.pack_uint(prog)
491+ self.pack_uint(vers)
492+ self.pack_uint(prot)
493+ self.pack_uint(port)
494+
495+ def pack_pmaplist(self, list):
496+ self.pack_list(list, self.pack_mapping)
497+
498+ def pack_call_args(self, ca):
499+ prog, vers, proc, args = ca
500+ self.pack_uint(prog)
501+ self.pack_uint(vers)
502+ self.pack_uint(proc)
503+ self.pack_opaque(args)
504+
505+
506+class PortMapperUnpacker(Unpacker):
507+
508+ def unpack_mapping(self):
509+ prog = self.unpack_uint()
510+ vers = self.unpack_uint()
511+ prot = self.unpack_uint()
512+ port = self.unpack_uint()
513+ return prog, vers, prot, port
514+
515+ def unpack_pmaplist(self):
516+ return self.unpack_list(self.unpack_mapping)
517+
518+ def unpack_call_result(self):
519+ port = self.unpack_uint()
520+ res = self.unpack_opaque()
521+ return port, res
522+
523+
524+class PartialPortMapperClient:
525+
526+ def addpackers(self):
527+ self.packer = PortMapperPacker()
528+ self.unpacker = PortMapperUnpacker('')
529+
530+ def Set(self, mapping):
531+ return self.make_call(PMAPPROC_SET, mapping, \
532+ self.packer.pack_mapping, \
533+ self.unpacker.unpack_uint)
534+
535+ def Unset(self, mapping):
536+ return self.make_call(PMAPPROC_UNSET, mapping, \
537+ self.packer.pack_mapping, \
538+ self.unpacker.unpack_uint)
539+
540+ def Getport(self, mapping):
541+ return self.make_call(PMAPPROC_GETPORT, mapping, \
542+ self.packer.pack_mapping, \
543+ self.unpacker.unpack_uint)
544+
545+ def Dump(self):
546+ return self.make_call(PMAPPROC_DUMP, None, \
547+ None, \
548+ self.unpacker.unpack_pmaplist)
549+
550+ def Callit(self, ca):
551+ return self.make_call(PMAPPROC_CALLIT, ca, \
552+ self.packer.pack_call_args, \
553+ self.unpacker.unpack_call_result)
554+
555+
556+class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient):
557+
558+ def __init__(self, host):
559+ RawTCPClient.__init__(self, \
560+ host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
561+
562+
563+class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient):
564+
565+ def __init__(self, host):
566+ RawUDPClient.__init__(self, \
567+ host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
568+
569+
570+class BroadcastUDPPortMapperClient(PartialPortMapperClient, \
571+ RawBroadcastUDPClient):
572+
573+ def __init__(self, bcastaddr):
574+ RawBroadcastUDPClient.__init__(self, \
575+ bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT)
576+
577+
578+# Generic clients that find their server through the Port mapper
579+
580+class TCPClient(RawTCPClient):
581+
582+ def __init__(self, host, prog, vers):
583+ pmap = TCPPortMapperClient(host)
584+ port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
585+ pmap.close()
586+ if port == 0:
587+ raise RuntimeError, 'program not registered'
588+ RawTCPClient.__init__(self, host, prog, vers, port)
589+
590+
591+class UDPClient(RawUDPClient):
592+
593+ def __init__(self, host, prog, vers):
594+ pmap = UDPPortMapperClient(host)
595+ port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
596+ pmap.close()
597+ if port == 0:
598+ raise RuntimeError, 'program not registered'
599+ RawUDPClient.__init__(self, host, prog, vers, port)
600+
601+
602+class BroadcastUDPClient(Client):
603+
604+ def __init__(self, bcastaddr, prog, vers):
605+ self.pmap = BroadcastUDPPortMapperClient(bcastaddr)
606+ self.pmap.set_reply_handler(self.my_reply_handler)
607+ self.prog = prog
608+ self.vers = vers
609+ self.user_reply_handler = None
610+ self.addpackers()
611+
612+ def close(self):
613+ self.pmap.close()
614+
615+ def set_reply_handler(self, reply_handler):
616+ self.user_reply_handler = reply_handler
617+
618+ def set_timeout(self, timeout):
619+ self.pmap.set_timeout(timeout)
620+
621+ def my_reply_handler(self, reply, fromaddr):
622+ port, res = reply
623+ self.unpacker.reset(res)
624+ result = self.unpack_func()
625+ self.unpacker.done()
626+ self.replies.append((result, fromaddr))
627+ if self.user_reply_handler is not None:
628+ self.user_reply_handler(result, fromaddr)
629+
630+ def make_call(self, proc, args, pack_func, unpack_func):
631+ self.packer.reset()
632+ if pack_func:
633+ pack_func(args)
634+ if unpack_func is None:
635+ def dummy(): pass
636+ self.unpack_func = dummy
637+ else:
638+ self.unpack_func = unpack_func
639+ self.replies = []
640+ packed_args = self.packer.get_buf()
641+ dummy_replies = self.pmap.Callit( \
642+ (self.prog, self.vers, proc, packed_args))
643+ return self.replies
644+
645+
646+# Server classes
647+
648+# These are not symmetric to the Client classes
649+# XXX No attempt is made to provide authorization hooks yet
650+
651+class Server:
652+
653+ def __init__(self, host, prog, vers, port):
654+ self.host = host # Should normally be '' for default interface
655+ self.prog = prog
656+ self.vers = vers
657+ self.port = port # Should normally be 0 for random port
658+ self.makesocket() # Assigns to self.sock and self.prot
659+ self.bindsocket()
660+ self.host, self.port = self.sock.getsockname()
661+ self.addpackers()
662+
663+ def register(self):
664+ mapping = self.prog, self.vers, self.prot, self.port
665+ p = TCPPortMapperClient(self.host)
666+ if not p.Set(mapping):
667+ raise RuntimeError, 'register failed'
668+
669+ def unregister(self):
670+ mapping = self.prog, self.vers, self.prot, self.port
671+ p = TCPPortMapperClient(self.host)
672+ if not p.Unset(mapping):
673+ raise RuntimeError, 'unregister failed'
674+
675+ def handle(self, call):
676+ # Don't use unpack_header but parse the header piecewise
677+ # XXX I have no idea if I am using the right error responses!
678+ self.unpacker.reset(call)
679+ self.packer.reset()
680+ xid = self.unpacker.unpack_uint()
681+ self.packer.pack_uint(xid)
682+ temp = self.unpacker.unpack_enum()
683+ if temp != CALL:
684+ return None # Not worthy of a reply
685+ self.packer.pack_uint(REPLY)
686+ temp = self.unpacker.unpack_uint()
687+ if temp != RPCVERSION:
688+ self.packer.pack_uint(MSG_DENIED)
689+ self.packer.pack_uint(RPC_MISMATCH)
690+ self.packer.pack_uint(RPCVERSION)
691+ self.packer.pack_uint(RPCVERSION)
692+ return self.packer.get_buf()
693+ self.packer.pack_uint(MSG_ACCEPTED)
694+ self.packer.pack_auth((AUTH_NULL, make_auth_null()))
695+ prog = self.unpacker.unpack_uint()
696+ if prog != self.prog:
697+ self.packer.pack_uint(PROG_UNAVAIL)
698+ return self.packer.get_buf()
699+ vers = self.unpacker.unpack_uint()
700+ if vers != self.vers:
701+ self.packer.pack_uint(PROG_MISMATCH)
702+ self.packer.pack_uint(self.vers)
703+ self.packer.pack_uint(self.vers)
704+ return self.packer.get_buf()
705+ proc = self.unpacker.unpack_uint()
706+ methname = 'handle_' + repr(proc)
707+ try:
708+ meth = getattr(self, methname)
709+ except AttributeError:
710+ self.packer.pack_uint(PROC_UNAVAIL)
711+ return self.packer.get_buf()
712+ cred = self.unpacker.unpack_auth()
713+ verf = self.unpacker.unpack_auth()
714+ try:
715+ meth() # Unpack args, call turn_around(), pack reply
716+ except (EOFError, GarbageArgs):
717+ # Too few or too many arguments
718+ self.packer.reset()
719+ self.packer.pack_uint(xid)
720+ self.packer.pack_uint(REPLY)
721+ self.packer.pack_uint(MSG_ACCEPTED)
722+ self.packer.pack_auth((AUTH_NULL, make_auth_null()))
723+ self.packer.pack_uint(GARBAGE_ARGS)
724+ return self.packer.get_buf()
725+
726+ def turn_around(self):
727+ try:
728+ self.unpacker.done()
729+ except RuntimeError:
730+ raise GarbageArgs
731+ self.packer.pack_uint(SUCCESS)
732+
733+ def handle_0(self): # Handle NULL message
734+ self.turn_around()
735+
736+ def makesocket(self):
737+ # This MUST be overridden
738+ raise RuntimeError, 'makesocket not defined'
739+
740+ def bindsocket(self):
741+ # Override this to bind to a different port (e.g. reserved)
742+ self.sock.bind((self.host, self.port))
743+
744+ def addpackers(self):
745+ # Override this to use derived classes from Packer/Unpacker
746+ self.packer = Packer()
747+ self.unpacker = Unpacker('')
748+
749+
750+class TCPServer(Server):
751+
752+ def makesocket(self):
753+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
754+ self.prot = IPPROTO_TCP
755+
756+ def loop(self):
757+ self.sock.listen(0)
758+ while 1:
759+ self.session(self.sock.accept())
760+
761+ def session(self, connection):
762+ sock, (host, port) = connection
763+ while 1:
764+ try:
765+ call = recvrecord(sock)
766+ except EOFError:
767+ break
768+ except socket.error, msg:
769+ print 'socket error:', msg
770+ break
771+ reply = self.handle(call)
772+ if reply is not None:
773+ sendrecord(sock, reply)
774+
775+ def forkingloop(self):
776+ # Like loop but uses forksession()
777+ self.sock.listen(0)
778+ while 1:
779+ self.forksession(self.sock.accept())
780+
781+ def forksession(self, connection):
782+ # Like session but forks off a subprocess
783+ import os
784+ # Wait for deceased children
785+ try:
786+ while 1:
787+ pid, sts = os.waitpid(0, 1)
788+ except os.error:
789+ pass
790+ pid = None
791+ try:
792+ pid = os.fork()
793+ if pid: # Parent
794+ connection[0].close()
795+ return
796+ # Child
797+ self.session(connection)
798+ finally:
799+ # Make sure we don't fall through in the parent
800+ if pid == 0:
801+ os._exit(0)
802+
803+
804+class UDPServer(Server):
805+
806+ def makesocket(self):
807+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
808+ self.prot = IPPROTO_UDP
809+
810+ def loop(self):
811+ while 1:
812+ self.session()
813+
814+ def session(self):
815+ call, host_port = self.sock.recvfrom(8192)
816+ reply = self.handle(call)
817+ if reply != None:
818+ self.sock.sendto(reply, host_port)
819+
820+
821+# Simple test program -- dump local portmapper status
822+
823+def test():
824+ pmap = UDPPortMapperClient('')
825+ list = pmap.Dump()
826+ list.sort()
827+ for prog, vers, prot, port in list:
828+ print prog, vers,
829+ if prot == IPPROTO_TCP: print 'tcp',
830+ elif prot == IPPROTO_UDP: print 'udp',
831+ else: print prot,
832+ print port
833+
834+
835+# Test program for broadcast operation -- dump everybody's portmapper status
836+
837+def testbcast():
838+ import sys
839+ if sys.argv[1:]:
840+ bcastaddr = sys.argv[1]
841+ else:
842+ bcastaddr = '<broadcast>'
843+ def rh(reply, fromaddr):
844+ host, port = fromaddr
845+ print host + '\t' + repr(reply)
846+ pmap = BroadcastUDPPortMapperClient(bcastaddr)
847+ pmap.set_reply_handler(rh)
848+ pmap.set_timeout(5)
849+ replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0))
850+
851+
852+# Test program for server, with corresponding client
853+# On machine A: python -c 'import rpc; rpc.testsvr()'
854+# On machine B: python -c 'import rpc; rpc.testclt()' A
855+# (A may be == B)
856+
857+def testsvr():
858+ # Simple test class -- proc 1 doubles its string argument as reply
859+ class S(UDPServer):
860+ def handle_1(self):
861+ arg = self.unpacker.unpack_string()
862+ self.turn_around()
863+ print 'RPC function 1 called, arg', repr(arg)
864+ self.packer.pack_string(arg + arg)
865+ #
866+ s = S('', 0x20000000, 1, 0)
867+ try:
868+ s.unregister()
869+ except RuntimeError, msg:
870+ print 'RuntimeError:', msg, '(ignored)'
871+ s.register()
872+ print 'Service started...'
873+ try:
874+ s.loop()
875+ finally:
876+ s.unregister()
877+ print 'Service interrupted.'
878+
879+
880+def testclt():
881+ import sys
882+ if sys.argv[1:]: host = sys.argv[1]
883+ else: host = ''
884+ # Client for above server
885+ class C(UDPClient):
886+ def call_1(self, arg):
887+ return self.make_call(1, arg, \
888+ self.packer.pack_string, \
889+ self.unpacker.unpack_string)
890+ c = C(host, 0x20000000, 1)
891+ print 'making call...'
892+ reply = c.call_1('hello, world, ')
893+ print 'call returned', repr(reply)
sys/src/cmd/python/Demo/rpc/test+24−0
@@ -0,0 +1,24 @@
1+: ${PYTHON=python}
2+: ${SERVER=charon.cwi.nl}
3+
4+set -xe
5+
6+$PYTHON -c 'from rpc import test; test()'
7+$PYTHON -c 'from rpc import test; test()' ${SERVER}
8+
9+$PYTHON -c 'from rpc import testsvr; testsvr()' &
10+PID=$!
11+sleep 2
12+$PYTHON -c 'from rpc import testclt; testclt()'
13+kill -2 $PID
14+
15+$PYTHON -c 'from mountclient import test; test()'
16+$PYTHON -c 'from mountclient import test; test()' gatekeeper.dec.com
17+
18+$PYTHON -c 'from nfsclient import test; test()'
19+$PYTHON -c 'from nfsclient import test; test()' gatekeeper.dec.com
20+$PYTHON -c 'from nfsclient import test; test()' gatekeeper.dec.com /archive
21+
22+$PYTHON -c 'from rnusersclient import test; test()' ''
23+
24+$PYTHON -c 'from rpc import testbcast; testbcast()'
sys/src/cmd/python/Demo/rpc/xdr.py+200−0
@@ -0,0 +1,200 @@
1+# Implement (a subset of) Sun XDR -- RFC1014.
2+
3+
4+try:
5+ import struct
6+except ImportError:
7+ struct = None
8+
9+
10+Long = type(0L)
11+
12+
13+class Packer:
14+
15+ def __init__(self):
16+ self.reset()
17+
18+ def reset(self):
19+ self.buf = ''
20+
21+ def get_buf(self):
22+ return self.buf
23+
24+ def pack_uint(self, x):
25+ self.buf = self.buf + \
26+ (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
27+ chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
28+ if struct and struct.pack('l', 1) == '\0\0\0\1':
29+ def pack_uint(self, x):
30+ if type(x) == Long:
31+ x = int((x + 0x80000000L) % 0x100000000L \
32+ - 0x80000000L)
33+ self.buf = self.buf + struct.pack('l', x)
34+
35+ pack_int = pack_uint
36+
37+ pack_enum = pack_int
38+
39+ def pack_bool(self, x):
40+ if x: self.buf = self.buf + '\0\0\0\1'
41+ else: self.buf = self.buf + '\0\0\0\0'
42+
43+ def pack_uhyper(self, x):
44+ self.pack_uint(int(x>>32 & 0xffffffff))
45+ self.pack_uint(int(x & 0xffffffff))
46+
47+ pack_hyper = pack_uhyper
48+
49+ def pack_float(self, x):
50+ # XXX
51+ self.buf = self.buf + struct.pack('f', x)
52+
53+ def pack_double(self, x):
54+ # XXX
55+ self.buf = self.buf + struct.pack('d', x)
56+
57+ def pack_fstring(self, n, s):
58+ if n < 0:
59+ raise ValueError, 'fstring size must be nonnegative'
60+ n = ((n+3)/4)*4
61+ data = s[:n]
62+ data = data + (n - len(data)) * '\0'
63+ self.buf = self.buf + data
64+
65+ pack_fopaque = pack_fstring
66+
67+ def pack_string(self, s):
68+ n = len(s)
69+ self.pack_uint(n)
70+ self.pack_fstring(n, s)
71+
72+ pack_opaque = pack_string
73+
74+ def pack_list(self, list, pack_item):
75+ for item in list:
76+ self.pack_uint(1)
77+ pack_item(item)
78+ self.pack_uint(0)
79+
80+ def pack_farray(self, n, list, pack_item):
81+ if len(list) <> n:
82+ raise ValueError, 'wrong array size'
83+ for item in list:
84+ pack_item(item)
85+
86+ def pack_array(self, list, pack_item):
87+ n = len(list)
88+ self.pack_uint(n)
89+ self.pack_farray(n, list, pack_item)
90+
91+
92+class Unpacker:
93+
94+ def __init__(self, data):
95+ self.reset(data)
96+
97+ def reset(self, data):
98+ self.buf = data
99+ self.pos = 0
100+
101+ def done(self):
102+ if self.pos < len(self.buf):
103+ raise RuntimeError, 'unextracted data remains'
104+
105+ def unpack_uint(self):
106+ i = self.pos
107+ self.pos = j = i+4
108+ data = self.buf[i:j]
109+ if len(data) < 4:
110+ raise EOFError
111+ x = long(ord(data[0]))<<24 | ord(data[1])<<16 | \
112+ ord(data[2])<<8 | ord(data[3])
113+ # Return a Python long only if the value is not representable
114+ # as a nonnegative Python int
115+ if x < 0x80000000L: x = int(x)
116+ return x
117+ if struct and struct.unpack('l', '\0\0\0\1') == 1:
118+ def unpack_uint(self):
119+ i = self.pos
120+ self.pos = j = i+4
121+ data = self.buf[i:j]
122+ if len(data) < 4:
123+ raise EOFError
124+ return struct.unpack('l', data)
125+
126+ def unpack_int(self):
127+ x = self.unpack_uint()
128+ if x >= 0x80000000L: x = x - 0x100000000L
129+ return int(x)
130+
131+ unpack_enum = unpack_int
132+
133+ unpack_bool = unpack_int
134+
135+ def unpack_uhyper(self):
136+ hi = self.unpack_uint()
137+ lo = self.unpack_uint()
138+ return long(hi)<<32 | lo
139+
140+ def unpack_hyper(self):
141+ x = self.unpack_uhyper()
142+ if x >= 0x8000000000000000L: x = x - 0x10000000000000000L
143+ return x
144+
145+ def unpack_float(self):
146+ # XXX
147+ i = self.pos
148+ self.pos = j = i+4
149+ data = self.buf[i:j]
150+ if len(data) < 4:
151+ raise EOFError
152+ return struct.unpack('f', data)[0]
153+
154+ def unpack_double(self):
155+ # XXX
156+ i = self.pos
157+ self.pos = j = i+8
158+ data = self.buf[i:j]
159+ if len(data) < 8:
160+ raise EOFError
161+ return struct.unpack('d', data)[0]
162+
163+ def unpack_fstring(self, n):
164+ if n < 0:
165+ raise ValueError, 'fstring size must be nonnegative'
166+ i = self.pos
167+ j = i + (n+3)/4*4
168+ if j > len(self.buf):
169+ raise EOFError
170+ self.pos = j
171+ return self.buf[i:i+n]
172+
173+ unpack_fopaque = unpack_fstring
174+
175+ def unpack_string(self):
176+ n = self.unpack_uint()
177+ return self.unpack_fstring(n)
178+
179+ unpack_opaque = unpack_string
180+
181+ def unpack_list(self, unpack_item):
182+ list = []
183+ while 1:
184+ x = self.unpack_uint()
185+ if x == 0: break
186+ if x <> 1:
187+ raise RuntimeError, '0 or 1 expected, got %r' % (x, )
188+ item = unpack_item()
189+ list.append(item)
190+ return list
191+
192+ def unpack_farray(self, n, unpack_item):
193+ list = []
194+ for i in range(n):
195+ list.append(unpack_item())
196+ return list
197+
198+ def unpack_array(self, unpack_item):
199+ n = self.unpack_uint()
200+ return self.unpack_farray(n, unpack_item)
sys/src/cmd/python/Demo/scripts/README+23−0
@@ -0,0 +1,23 @@
1+This directory contains a collection of executable Python scripts.
2+
3+See also the Tools/scripts directory!
4+
5+beer.py Print the classic 'bottles of beer' list.
6+eqfix.py Fix .py files to use the correct equality test operator
7+fact.py Factorize numbers
8+find-uname.py Search for Unicode characters using regexps.
9+from.py Summarize mailbox
10+ftpstats.py Summarize ftp daemon log file
11+lpwatch.py Watch BSD line printer queues
12+makedir.py Like mkdir -p
13+markov.py Markov chain simulation of words or characters
14+mboxconvvert.py Convert MH or MMDF mailboxes to unix mailbox format
15+mkrcs.py Fix symlinks named RCS into parallel tree
16+morse.py Produce morse code (audible or on AIFF file)
17+pi.py Print all digits of pi -- given enough time and memory
18+pp.py Emulate some Perl command line options
19+primes.py Print prime numbers
20+queens.py Dijkstra's solution to Wirth's "N Queens problem"
21+script.py Equivalent to BSD script(1) -- by Steen Lumholt
22+unbirthday.py Print unbirthday count
23+update.py Update a bunch of files according to a script.
sys/src/cmd/python/Demo/scripts/beer.py+14−0
@@ -0,0 +1,14 @@
1+#! /usr/bin/env python
2+# By GvR, demystified after a version by Fredrik Lundh.
3+import sys
4+n = 100
5+if sys.argv[1:]: n = int(sys.argv[1])
6+def bottle(n):
7+ if n == 0: return "no more bottles of beer"
8+ if n == 1: return "one bottle of beer"
9+ return str(n) + " bottles of beer"
10+for i in range(n):
11+ print bottle(n-i), "on the wall,"
12+ print bottle(n-i) + "."
13+ print "Take one down, pass it around,"
14+ print bottle(n-i-1), "on the wall."
sys/src/cmd/python/Demo/scripts/eqfix.py+198−0
@@ -0,0 +1,198 @@
1+#! /usr/bin/env python
2+
3+# Fix Python source files to use the new equality test operator, i.e.,
4+# if x = y: ...
5+# is changed to
6+# if x == y: ...
7+# The script correctly tokenizes the Python program to reliably
8+# distinguish between assignments and equality tests.
9+#
10+# Command line arguments are files or directories to be processed.
11+# Directories are searched recursively for files whose name looks
12+# like a python module.
13+# Symbolic links are always ignored (except as explicit directory
14+# arguments). Of course, the original file is kept as a back-up
15+# (with a "~" attached to its name).
16+# It complains about binaries (files containing null bytes)
17+# and about files that are ostensibly not Python files: if the first
18+# line starts with '#!' and does not contain the string 'python'.
19+#
20+# Changes made are reported to stdout in a diff-like format.
21+#
22+# Undoubtedly you can do this using find and sed or perl, but this is
23+# a nice example of Python code that recurses down a directory tree
24+# and uses regular expressions. Also note several subtleties like
25+# preserving the file's mode and avoiding to even write a temp file
26+# when no changes are needed for a file.
27+#
28+# NB: by changing only the function fixline() you can turn this
29+# into a program for a different change to Python programs...
30+
31+import sys
32+import re
33+import os
34+from stat import *
35+import string
36+
37+err = sys.stderr.write
38+dbg = err
39+rep = sys.stdout.write
40+
41+def main():
42+ bad = 0
43+ if not sys.argv[1:]: # No arguments
44+ err('usage: ' + sys.argv[0] + ' file-or-directory ...\n')
45+ sys.exit(2)
46+ for arg in sys.argv[1:]:
47+ if os.path.isdir(arg):
48+ if recursedown(arg): bad = 1
49+ elif os.path.islink(arg):
50+ err(arg + ': will not process symbolic links\n')
51+ bad = 1
52+ else:
53+ if fix(arg): bad = 1
54+ sys.exit(bad)
55+
56+ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$')
57+def ispython(name):
58+ return ispythonprog.match(name) >= 0
59+
60+def recursedown(dirname):
61+ dbg('recursedown(%r)\n' % (dirname,))
62+ bad = 0
63+ try:
64+ names = os.listdir(dirname)
65+ except os.error, msg:
66+ err('%s: cannot list directory: %r\n' % (dirname, msg))
67+ return 1
68+ names.sort()
69+ subdirs = []
70+ for name in names:
71+ if name in (os.curdir, os.pardir): continue
72+ fullname = os.path.join(dirname, name)
73+ if os.path.islink(fullname): pass
74+ elif os.path.isdir(fullname):
75+ subdirs.append(fullname)
76+ elif ispython(name):
77+ if fix(fullname): bad = 1
78+ for fullname in subdirs:
79+ if recursedown(fullname): bad = 1
80+ return bad
81+
82+def fix(filename):
83+## dbg('fix(%r)\n' % (dirname,))
84+ try:
85+ f = open(filename, 'r')
86+ except IOError, msg:
87+ err('%s: cannot open: %r\n' % (filename, msg))
88+ return 1
89+ head, tail = os.path.split(filename)
90+ tempname = os.path.join(head, '@' + tail)
91+ g = None
92+ # If we find a match, we rewind the file and start over but
93+ # now copy everything to a temp file.
94+ lineno = 0
95+ while 1:
96+ line = f.readline()
97+ if not line: break
98+ lineno = lineno + 1
99+ if g is None and '\0' in line:
100+ # Check for binary files
101+ err(filename + ': contains null bytes; not fixed\n')
102+ f.close()
103+ return 1
104+ if lineno == 1 and g is None and line[:2] == '#!':
105+ # Check for non-Python scripts
106+ words = string.split(line[2:])
107+ if words and re.search('[pP]ython', words[0]) < 0:
108+ msg = filename + ': ' + words[0]
109+ msg = msg + ' script; not fixed\n'
110+ err(msg)
111+ f.close()
112+ return 1
113+ while line[-2:] == '\\\n':
114+ nextline = f.readline()
115+ if not nextline: break
116+ line = line + nextline
117+ lineno = lineno + 1
118+ newline = fixline(line)
119+ if newline != line:
120+ if g is None:
121+ try:
122+ g = open(tempname, 'w')
123+ except IOError, msg:
124+ f.close()
125+ err('%s: cannot create: %r\n' % (tempname, msg))
126+ return 1
127+ f.seek(0)
128+ lineno = 0
129+ rep(filename + ':\n')
130+ continue # restart from the beginning
131+ rep(repr(lineno) + '\n')
132+ rep('< ' + line)
133+ rep('> ' + newline)
134+ if g is not None:
135+ g.write(newline)
136+
137+ # End of file
138+ f.close()
139+ if not g: return 0 # No changes
140+
141+ # Finishing touch -- move files
142+
143+ # First copy the file's mode to the temp file
144+ try:
145+ statbuf = os.stat(filename)
146+ os.chmod(tempname, statbuf[ST_MODE] & 07777)
147+ except os.error, msg:
148+ err('%s: warning: chmod failed (%r)\n' % (tempname, msg))
149+ # Then make a backup of the original file as filename~
150+ try:
151+ os.rename(filename, filename + '~')
152+ except os.error, msg:
153+ err('%s: warning: backup failed (%r)\n' % (filename, msg))
154+ # Now move the temp file to the original file
155+ try:
156+ os.rename(tempname, filename)
157+ except os.error, msg:
158+ err('%s: rename failed (%r)\n' % (filename, msg))
159+ return 1
160+ # Return succes
161+ return 0
162+
163+
164+from tokenize import tokenprog
165+
166+match = {'if':':', 'elif':':', 'while':':', 'return':'\n', \
167+ '(':')', '[':']', '{':'}', '`':'`'}
168+
169+def fixline(line):
170+ # Quick check for easy case
171+ if '=' not in line: return line
172+
173+ i, n = 0, len(line)
174+ stack = []
175+ while i < n:
176+ j = tokenprog.match(line, i)
177+ if j < 0:
178+ # A bad token; forget about the rest of this line
179+ print '(Syntax error:)'
180+ print line,
181+ return line
182+ a, b = tokenprog.regs[3] # Location of the token proper
183+ token = line[a:b]
184+ i = i+j
185+ if stack and token == stack[-1]:
186+ del stack[-1]
187+ elif match.has_key(token):
188+ stack.append(match[token])
189+ elif token == '=' and stack:
190+ line = line[:a] + '==' + line[b:]
191+ i, n = a + len('=='), len(line)
192+ elif token == '==' and not stack:
193+ print '(Warning: \'==\' at top level:)'
194+ print line,
195+ return line
196+
197+if __name__ == "__main__":
198+ main()
sys/src/cmd/python/Demo/scripts/fact.py+49−0
@@ -0,0 +1,49 @@
1+#! /usr/bin/env python
2+
3+# Factorize numbers.
4+# The algorithm is not efficient, but easy to understand.
5+# If there are large factors, it will take forever to find them,
6+# because we try all odd numbers between 3 and sqrt(n)...
7+
8+import sys
9+from math import sqrt
10+
11+error = 'fact.error' # exception
12+
13+def fact(n):
14+ if n < 1: raise error # fact() argument should be >= 1
15+ if n == 1: return [] # special case
16+ res = []
17+ # Treat even factors special, so we can use i = i+2 later
18+ while n%2 == 0:
19+ res.append(2)
20+ n = n/2
21+ # Try odd numbers up to sqrt(n)
22+ limit = sqrt(float(n+1))
23+ i = 3
24+ while i <= limit:
25+ if n%i == 0:
26+ res.append(i)
27+ n = n/i
28+ limit = sqrt(n+1)
29+ else:
30+ i = i+2
31+ if n != 1:
32+ res.append(n)
33+ return res
34+
35+def main():
36+ if len(sys.argv) > 1:
37+ for arg in sys.argv[1:]:
38+ n = eval(arg)
39+ print n, fact(n)
40+ else:
41+ try:
42+ while 1:
43+ n = input()
44+ print n, fact(n)
45+ except EOFError:
46+ pass
47+
48+if __name__ == "__main__":
49+ main()
sys/src/cmd/python/Demo/scripts/find-uname.py+40−0
@@ -0,0 +1,40 @@
1+#!/usr/bin/env python
2+
3+"""
4+For each argument on the command line, look for it in the set of all Unicode
5+names. Arguments are treated as case-insensitive regular expressions, e.g.:
6+
7+ % find-uname 'small letter a$' 'horizontal line'
8+ *** small letter a$ matches ***
9+ LATIN SMALL LETTER A (97)
10+ COMBINING LATIN SMALL LETTER A (867)
11+ CYRILLIC SMALL LETTER A (1072)
12+ PARENTHESIZED LATIN SMALL LETTER A (9372)
13+ CIRCLED LATIN SMALL LETTER A (9424)
14+ FULLWIDTH LATIN SMALL LETTER A (65345)
15+ *** horizontal line matches ***
16+ HORIZONTAL LINE EXTENSION (9135)
17+"""
18+
19+import unicodedata
20+import sys
21+import re
22+
23+def main(args):
24+ unicode_names= []
25+ for ix in range(sys.maxunicode+1):
26+ try:
27+ unicode_names.append( (ix, unicodedata.name(unichr(ix))) )
28+ except ValueError: # no name for the character
29+ pass
30+ for arg in args:
31+ pat = re.compile(arg, re.I)
32+ matches = [(x,y) for (x,y) in unicode_names
33+ if pat.search(y) is not None]
34+ if matches:
35+ print "***", arg, "matches", "***"
36+ for (x,y) in matches:
37+ print "%s (%d)" % (y,x)
38+
39+if __name__ == "__main__":
40+ main(sys.argv[1:])
sys/src/cmd/python/Demo/scripts/from.py+35−0
@@ -0,0 +1,35 @@
1+#! /usr/bin/env python
2+
3+# Print From and Subject of messages in $MAIL.
4+# Extension to multiple mailboxes and other bells & whistles are left
5+# as exercises for the reader.
6+
7+import sys, os
8+
9+# Open mailbox file. Exits with exception when this fails.
10+
11+try:
12+ mailbox = os.environ['MAIL']
13+except (AttributeError, KeyError):
14+ sys.stderr.write('No environment variable $MAIL\n')
15+ sys.exit(2)
16+
17+try:
18+ mail = open(mailbox)
19+except IOError:
20+ sys.exit('Cannot open mailbox file: ' + mailbox)
21+
22+while 1:
23+ line = mail.readline()
24+ if not line:
25+ break # EOF
26+ if line.startswith('From '):
27+ # Start of message found
28+ print line[:-1],
29+ while 1:
30+ line = mail.readline()
31+ if not line or line == '\n':
32+ break
33+ if line.startswith('Subject: '):
34+ print repr(line[9:-1]),
35+ print
sys/src/cmd/python/Demo/scripts/ftpstats.py+145−0
@@ -0,0 +1,145 @@
1+#! /usr/bin/env python
2+
3+# Extract statistics from ftp daemon log.
4+
5+# Usage:
6+# ftpstats [-m maxitems] [-s search] [file]
7+# -m maxitems: restrict number of items in "top-N" lists, default 25.
8+# -s string: restrict statistics to lines containing this string.
9+# Default file is /usr/adm/ftpd; a "-" means read standard input.
10+
11+# The script must be run on the host where the ftp daemon runs.
12+# (At CWI this is currently buizerd.)
13+
14+import os
15+import sys
16+import re
17+import string
18+import getopt
19+
20+pat = '^([a-zA-Z0-9 :]*)!(.*)!(.*)!([<>].*)!([0-9]+)!([0-9]+)$'
21+prog = re.compile(pat)
22+
23+def main():
24+ maxitems = 25
25+ search = None
26+ try:
27+ opts, args = getopt.getopt(sys.argv[1:], 'm:s:')
28+ except getopt.error, msg:
29+ print msg
30+ print 'usage: ftpstats [-m maxitems] [file]'
31+ sys.exit(2)
32+ for o, a in opts:
33+ if o == '-m':
34+ maxitems = string.atoi(a)
35+ if o == '-s':
36+ search = a
37+ file = '/usr/adm/ftpd'
38+ if args: file = args[0]
39+ if file == '-':
40+ f = sys.stdin
41+ else:
42+ try:
43+ f = open(file, 'r')
44+ except IOError, msg:
45+ print file, ':', msg
46+ sys.exit(1)
47+ bydate = {}
48+ bytime = {}
49+ byfile = {}
50+ bydir = {}
51+ byhost = {}
52+ byuser = {}
53+ bytype = {}
54+ lineno = 0
55+ try:
56+ while 1:
57+ line = f.readline()
58+ if not line: break
59+ lineno = lineno + 1
60+ if search and string.find(line, search) < 0:
61+ continue
62+ if prog.match(line) < 0:
63+ print 'Bad line', lineno, ':', repr(line)
64+ continue
65+ items = prog.group(1, 2, 3, 4, 5, 6)
66+ (logtime, loguser, loghost, logfile, logbytes,
67+ logxxx2) = items
68+## print logtime
69+## print '-->', loguser
70+## print '--> -->', loghost
71+## print '--> --> -->', logfile
72+## print '--> --> --> -->', logbytes
73+## print '--> --> --> --> -->', logxxx2
74+## for i in logtime, loghost, logbytes, logxxx2:
75+## if '!' in i: print '???', i
76+ add(bydate, logtime[-4:] + ' ' + logtime[:6], items)
77+ add(bytime, logtime[7:9] + ':00-59', items)
78+ direction, logfile = logfile[0], logfile[1:]
79+ # The real path probably starts at the last //...
80+ while 1:
81+ i = string.find(logfile, '//')
82+ if i < 0: break
83+ logfile = logfile[i+1:]
84+ add(byfile, logfile + ' ' + direction, items)
85+ logdir = os.path.dirname(logfile)
86+## logdir = os.path.normpath(logdir) + '/.'
87+ while 1:
88+ add(bydir, logdir + ' ' + direction, items)
89+ dirhead = os.path.dirname(logdir)
90+ if dirhead == logdir: break
91+ logdir = dirhead
92+ add(byhost, loghost, items)
93+ add(byuser, loguser, items)
94+ add(bytype, direction, items)
95+ except KeyboardInterrupt:
96+ print 'Interrupted at line', lineno
97+ show(bytype, 'by transfer direction', maxitems)
98+ show(bydir, 'by directory', maxitems)
99+ show(byfile, 'by file', maxitems)
100+ show(byhost, 'by host', maxitems)
101+ show(byuser, 'by user', maxitems)
102+ showbar(bydate, 'by date')
103+ showbar(bytime, 'by time of day')
104+
105+def showbar(dict, title):
106+ n = len(title)
107+ print '='*((70-n)/2), title, '='*((71-n)/2)
108+ list = []
109+ keys = dict.keys()
110+ keys.sort()
111+ for key in keys:
112+ n = len(str(key))
113+ list.append((len(dict[key]), key))
114+ maxkeylength = 0
115+ maxcount = 0
116+ for count, key in list:
117+ maxkeylength = max(maxkeylength, len(key))
118+ maxcount = max(maxcount, count)
119+ maxbarlength = 72 - maxkeylength - 7
120+ for count, key in list:
121+ barlength = int(round(maxbarlength*float(count)/maxcount))
122+ bar = '*'*barlength
123+ print '%5d %-*s %s' % (count, maxkeylength, key, bar)
124+
125+def show(dict, title, maxitems):
126+ if len(dict) > maxitems:
127+ title = title + ' (first %d)'%maxitems
128+ n = len(title)
129+ print '='*((70-n)/2), title, '='*((71-n)/2)
130+ list = []
131+ keys = dict.keys()
132+ for key in keys:
133+ list.append((-len(dict[key]), key))
134+ list.sort()
135+ for count, key in list[:maxitems]:
136+ print '%5d %s' % (-count, key)
137+
138+def add(dict, key, item):
139+ if dict.has_key(key):
140+ dict[key].append(item)
141+ else:
142+ dict[key] = [item]
143+
144+if __name__ == "__main__":
145+ main()
sys/src/cmd/python/Demo/scripts/lpwatch.py+110−0
@@ -0,0 +1,110 @@
1+#! /usr/bin/env python
2+
3+# Watch line printer queue(s).
4+# Intended for BSD 4.3 lpq.
5+
6+import posix
7+import sys
8+import time
9+import string
10+
11+DEF_PRINTER = 'psc'
12+DEF_DELAY = 10
13+
14+def main():
15+ delay = DEF_DELAY # XXX Use getopt() later
16+ try:
17+ thisuser = posix.environ['LOGNAME']
18+ except:
19+ thisuser = posix.environ['USER']
20+ printers = sys.argv[1:]
21+ if printers:
22+ # Strip '-P' from printer names just in case
23+ # the user specified it...
24+ for i in range(len(printers)):
25+ if printers[i][:2] == '-P':
26+ printers[i] = printers[i][2:]
27+ else:
28+ if posix.environ.has_key('PRINTER'):
29+ printers = [posix.environ['PRINTER']]
30+ else:
31+ printers = [DEF_PRINTER]
32+ #
33+ clearhome = posix.popen('clear', 'r').read()
34+ #
35+ while 1:
36+ text = clearhome
37+ for name in printers:
38+ text = text + makestatus(name, thisuser) + '\n'
39+ print text
40+ time.sleep(delay)
41+
42+def makestatus(name, thisuser):
43+ pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r')
44+ lines = []
45+ users = {}
46+ aheadbytes = 0
47+ aheadjobs = 0
48+ userseen = 0
49+ totalbytes = 0
50+ totaljobs = 0
51+ while 1:
52+ line = pipe.readline()
53+ if not line: break
54+ fields = string.split(line)
55+ n = len(fields)
56+ if len(fields) >= 6 and fields[n-1] == 'bytes':
57+ rank = fields[0]
58+ user = fields[1]
59+ job = fields[2]
60+ files = fields[3:-2]
61+ bytes = eval(fields[n-2])
62+ if user == thisuser:
63+ userseen = 1
64+ elif not userseen:
65+ aheadbytes = aheadbytes + bytes
66+ aheadjobs = aheadjobs + 1
67+ totalbytes = totalbytes + bytes
68+ totaljobs = totaljobs + 1
69+ if users.has_key(user):
70+ ujobs, ubytes = users[user]
71+ else:
72+ ujobs, ubytes = 0, 0
73+ ujobs = ujobs + 1
74+ ubytes = ubytes + bytes
75+ users[user] = ujobs, ubytes
76+ else:
77+ if fields and fields[0] <> 'Rank':
78+ line = string.strip(line)
79+ if line == 'no entries':
80+ line = name + ': idle'
81+ elif line[-22:] == ' is ready and printing':
82+ line = name
83+ lines.append(line)
84+ #
85+ if totaljobs:
86+ line = '%d K' % ((totalbytes+1023)/1024)
87+ if totaljobs <> len(users):
88+ line = line + ' (%d jobs)' % totaljobs
89+ if len(users) == 1:
90+ line = line + ' for %s' % (users.keys()[0],)
91+ else:
92+ line = line + ' for %d users' % len(users)
93+ if userseen:
94+ if aheadjobs == 0:
95+ line = line + ' (%s first)' % thisuser
96+ else:
97+ line = line + ' (%d K before %s)' % (
98+ (aheadbytes+1023)/1024, thisuser)
99+ lines.append(line)
100+ #
101+ sts = pipe.close()
102+ if sts:
103+ lines.append('lpq exit status %r' % (sts,))
104+ return string.joinfields(lines, ': ')
105+
106+if __name__ == "__main__":
107+ try:
108+ main()
109+ except KeyboardInterrupt:
110+ pass
sys/src/cmd/python/Demo/scripts/makedir.py+21−0
@@ -0,0 +1,21 @@
1+#! /usr/bin/env python
2+
3+# Like mkdir, but also make intermediate directories if necessary.
4+# It is not an error if the given directory already exists (as long
5+# as it is a directory).
6+# Errors are not treated specially -- you just get a Python exception.
7+
8+import sys, os
9+
10+def main():
11+ for p in sys.argv[1:]:
12+ makedirs(p)
13+
14+def makedirs(p):
15+ if p and not os.path.isdir(p):
16+ head, tail = os.path.split(p)
17+ makedirs(head)
18+ os.mkdir(p, 0777)
19+
20+if __name__ == "__main__":
21+ main()
sys/src/cmd/python/Demo/scripts/markov.py+117−0
@@ -0,0 +1,117 @@
1+#! /usr/bin/env python
2+
3+class Markov:
4+ def __init__(self, histsize, choice):
5+ self.histsize = histsize
6+ self.choice = choice
7+ self.trans = {}
8+ def add(self, state, next):
9+ if not self.trans.has_key(state):
10+ self.trans[state] = [next]
11+ else:
12+ self.trans[state].append(next)
13+ def put(self, seq):
14+ n = self.histsize
15+ add = self.add
16+ add(None, seq[:0])
17+ for i in range(len(seq)):
18+ add(seq[max(0, i-n):i], seq[i:i+1])
19+ add(seq[len(seq)-n:], None)
20+ def get(self):
21+ choice = self.choice
22+ trans = self.trans
23+ n = self.histsize
24+ seq = choice(trans[None])
25+ while 1:
26+ subseq = seq[max(0, len(seq)-n):]
27+ options = trans[subseq]
28+ next = choice(options)
29+ if not next: break
30+ seq = seq + next
31+ return seq
32+
33+def test():
34+ import sys, string, random, getopt
35+ args = sys.argv[1:]
36+ try:
37+ opts, args = getopt.getopt(args, '0123456789cdw')
38+ except getopt.error:
39+ print 'Usage: markov [-#] [-cddqw] [file] ...'
40+ print 'Options:'
41+ print '-#: 1-digit history size (default 2)'
42+ print '-c: characters (default)'
43+ print '-w: words'
44+ print '-d: more debugging output'
45+ print '-q: no debugging output'
46+ print 'Input files (default stdin) are split in paragraphs'
47+ print 'separated blank lines and each paragraph is split'
48+ print 'in words by whitespace, then reconcatenated with'
49+ print 'exactly one space separating words.'
50+ print 'Output consists of paragraphs separated by blank'
51+ print 'lines, where lines are no longer than 72 characters.'
52+ histsize = 2
53+ do_words = 0
54+ debug = 1
55+ for o, a in opts:
56+ if '-0' <= o <= '-9': histsize = eval(o[1:])
57+ if o == '-c': do_words = 0
58+ if o == '-d': debug = debug + 1
59+ if o == '-q': debug = 0
60+ if o == '-w': do_words = 1
61+ if not args: args = ['-']
62+ m = Markov(histsize, random.choice)
63+ try:
64+ for filename in args:
65+ if filename == '-':
66+ f = sys.stdin
67+ if f.isatty():
68+ print 'Sorry, need stdin from file'
69+ continue
70+ else:
71+ f = open(filename, 'r')
72+ if debug: print 'processing', filename, '...'
73+ text = f.read()
74+ f.close()
75+ paralist = string.splitfields(text, '\n\n')
76+ for para in paralist:
77+ if debug > 1: print 'feeding ...'
78+ words = string.split(para)
79+ if words:
80+ if do_words: data = tuple(words)
81+ else: data = string.joinfields(words, ' ')
82+ m.put(data)
83+ except KeyboardInterrupt:
84+ print 'Interrupted -- continue with data read so far'
85+ if not m.trans:
86+ print 'No valid input files'
87+ return
88+ if debug: print 'done.'
89+ if debug > 1:
90+ for key in m.trans.keys():
91+ if key is None or len(key) < histsize:
92+ print repr(key), m.trans[key]
93+ if histsize == 0: print repr(''), m.trans['']
94+ print
95+ while 1:
96+ data = m.get()
97+ if do_words: words = data
98+ else: words = string.split(data)
99+ n = 0
100+ limit = 72
101+ for w in words:
102+ if n + len(w) > limit:
103+ print
104+ n = 0
105+ print w,
106+ n = n + len(w) + 1
107+ print
108+ print
109+
110+def tuple(list):
111+ if len(list) == 0: return ()
112+ if len(list) == 1: return (list[0],)
113+ i = len(list)/2
114+ return tuple(list[:i]) + tuple(list[i:])
115+
116+if __name__ == "__main__":
117+ test()
sys/src/cmd/python/Demo/scripts/mboxconvert.py+124−0
@@ -0,0 +1,124 @@
1+#! /usr/bin/env python
2+
3+# Convert MH directories (1 message per file) or MMDF mailboxes (4x^A
4+# delimited) to unix mailbox (From ... delimited) on stdout.
5+# If -f is given, files contain one message per file (e.g. MH messages)
6+
7+import rfc822
8+import sys
9+import time
10+import os
11+import stat
12+import getopt
13+import re
14+
15+def main():
16+ dofile = mmdf
17+ try:
18+ opts, args = getopt.getopt(sys.argv[1:], 'f')
19+ except getopt.error, msg:
20+ sys.stderr.write('%s\n' % msg)
21+ sys.exit(2)
22+ for o, a in opts:
23+ if o == '-f':
24+ dofile = message
25+ if not args:
26+ args = ['-']
27+ sts = 0
28+ for arg in args:
29+ if arg == '-' or arg == '':
30+ sts = dofile(sys.stdin) or sts
31+ elif os.path.isdir(arg):
32+ sts = mh(arg) or sts
33+ elif os.path.isfile(arg):
34+ try:
35+ f = open(arg)
36+ except IOError, msg:
37+ sys.stderr.write('%s: %s\n' % (arg, msg))
38+ sts = 1
39+ continue
40+ sts = dofile(f) or sts
41+ f.close()
42+ else:
43+ sys.stderr.write('%s: not found\n' % arg)
44+ sts = 1
45+ if sts:
46+ sys.exit(sts)
47+
48+numeric = re.compile('[1-9][0-9]*')
49+
50+def mh(dir):
51+ sts = 0
52+ msgs = os.listdir(dir)
53+ for msg in msgs:
54+ if numeric.match(msg) != len(msg):
55+ continue
56+ fn = os.path.join(dir, msg)
57+ try:
58+ f = open(fn)
59+ except IOError, msg:
60+ sys.stderr.write('%s: %s\n' % (fn, msg))
61+ sts = 1
62+ continue
63+ sts = message(f) or sts
64+ return sts
65+
66+def mmdf(f):
67+ sts = 0
68+ while 1:
69+ line = f.readline()
70+ if not line:
71+ break
72+ if line == '\1\1\1\1\n':
73+ sts = message(f, line) or sts
74+ else:
75+ sys.stderr.write(
76+ 'Bad line in MMFD mailbox: %r\n' % (line,))
77+ return sts
78+
79+counter = 0 # for generating unique Message-ID headers
80+
81+def message(f, delimiter = ''):
82+ sts = 0
83+ # Parse RFC822 header
84+ m = rfc822.Message(f)
85+ # Write unix header line
86+ fullname, email = m.getaddr('From')
87+ tt = m.getdate('Date')
88+ if tt:
89+ t = time.mktime(tt)
90+ else:
91+ sys.stderr.write(
92+ 'Unparseable date: %r\n' % (m.getheader('Date'),))
93+ t = os.fstat(f.fileno())[stat.ST_MTIME]
94+ print 'From', email, time.ctime(t)
95+ # Copy RFC822 header
96+ for line in m.headers:
97+ print line,
98+ # Invent Message-ID header if none is present
99+ if not m.has_key('message-id'):
100+ global counter
101+ counter = counter + 1
102+ msgid = "<%s.%d>" % (hex(t), counter)
103+ sys.stderr.write("Adding Message-ID %s (From %s)\n" %
104+ (msgid, email))
105+ print "Message-ID:", msgid
106+ print
107+ # Copy body
108+ while 1:
109+ line = f.readline()
110+ if line == delimiter:
111+ break
112+ if not line:
113+ sys.stderr.write('Unexpected EOF in message\n')
114+ sts = 1
115+ break
116+ if line[:5] == 'From ':
117+ line = '>' + line
118+ print line,
119+ # Print trailing newline
120+ print
121+ return sts
122+
123+if __name__ == "__main__":
124+ main()
sys/src/cmd/python/Demo/scripts/mkrcs.py+61−0
@@ -0,0 +1,61 @@
1+#! /usr/bin/env python
2+
3+# A rather specialized script to make sure that a symbolic link named
4+# RCS exists pointing to a real RCS directory in a parallel tree
5+# referenced as RCStree in an ancestor directory.
6+# (I use this because I like my RCS files to reside on a physically
7+# different machine).
8+
9+import os
10+
11+def main():
12+ rcstree = 'RCStree'
13+ rcs = 'RCS'
14+ if os.path.islink(rcs):
15+ print '%r is a symlink to %r' % (rcs, os.readlink(rcs))
16+ return
17+ if os.path.isdir(rcs):
18+ print '%r is an ordinary directory' % (rcs,)
19+ return
20+ if os.path.exists(rcs):
21+ print '%r is a file?!?!' % (rcs,)
22+ return
23+ #
24+ p = os.getcwd()
25+ up = ''
26+ down = ''
27+ # Invariants:
28+ # (1) join(p, down) is the current directory
29+ # (2) up is the same directory as p
30+ # Ergo:
31+ # (3) join(up, down) is the current directory
32+ #print 'p =', repr(p)
33+ while not os.path.isdir(os.path.join(p, rcstree)):
34+ head, tail = os.path.split(p)
35+ #print 'head = %r; tail = %r' % (head, tail)
36+ if not tail:
37+ print 'Sorry, no ancestor dir contains %r' % (rcstree,)
38+ return
39+ p = head
40+ up = os.path.join(os.pardir, up)
41+ down = os.path.join(tail, down)
42+ #print 'p = %r; up = %r; down = %r' % (p, up, down)
43+ there = os.path.join(up, rcstree)
44+ there = os.path.join(there, down)
45+ there = os.path.join(there, rcs)
46+ if os.path.isdir(there):
47+ print '%r already exists' % (there, )
48+ else:
49+ print 'making %r' % (there,)
50+ makedirs(there)
51+ print 'making symlink %r -> %r' % (rcs, there)
52+ os.symlink(there, rcs)
53+
54+def makedirs(p):
55+ if not os.path.isdir(p):
56+ head, tail = os.path.split(p)
57+ makedirs(head)
58+ os.mkdir(p, 0777)
59+
60+if __name__ == "__main__":
61+ main()
sys/src/cmd/python/Demo/scripts/morse.py+149−0
@@ -0,0 +1,149 @@
1+# DAH should be three DOTs.
2+# Space between DOTs and DAHs should be one DOT.
3+# Space between two letters should be one DAH.
4+# Space between two words should be DOT DAH DAH.
5+
6+import sys, math, audiodev
7+
8+DOT = 30
9+DAH = 3 * DOT
10+OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ...
11+
12+morsetab = {
13+ 'A': '.-', 'a': '.-',
14+ 'B': '-...', 'b': '-...',
15+ 'C': '-.-.', 'c': '-.-.',
16+ 'D': '-..', 'd': '-..',
17+ 'E': '.', 'e': '.',
18+ 'F': '..-.', 'f': '..-.',
19+ 'G': '--.', 'g': '--.',
20+ 'H': '....', 'h': '....',
21+ 'I': '..', 'i': '..',
22+ 'J': '.---', 'j': '.---',
23+ 'K': '-.-', 'k': '-.-',
24+ 'L': '.-..', 'l': '.-..',
25+ 'M': '--', 'm': '--',
26+ 'N': '-.', 'n': '-.',
27+ 'O': '---', 'o': '---',
28+ 'P': '.--.', 'p': '.--.',
29+ 'Q': '--.-', 'q': '--.-',
30+ 'R': '.-.', 'r': '.-.',
31+ 'S': '...', 's': '...',
32+ 'T': '-', 't': '-',
33+ 'U': '..-', 'u': '..-',
34+ 'V': '...-', 'v': '...-',
35+ 'W': '.--', 'w': '.--',
36+ 'X': '-..-', 'x': '-..-',
37+ 'Y': '-.--', 'y': '-.--',
38+ 'Z': '--..', 'z': '--..',
39+ '0': '-----',
40+ '1': '.----',
41+ '2': '..---',
42+ '3': '...--',
43+ '4': '....-',
44+ '5': '.....',
45+ '6': '-....',
46+ '7': '--...',
47+ '8': '---..',
48+ '9': '----.',
49+ ',': '--..--',
50+ '.': '.-.-.-',
51+ '?': '..--..',
52+ ';': '-.-.-.',
53+ ':': '---...',
54+ "'": '.----.',
55+ '-': '-....-',
56+ '/': '-..-.',
57+ '(': '-.--.-',
58+ ')': '-.--.-',
59+ '_': '..--.-',
60+ ' ': ' '
61+}
62+
63+# If we play at 44.1 kHz (which we do), then if we produce one sine
64+# wave in 100 samples, we get a tone of 441 Hz. If we produce two
65+# sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz
66+# appears to be a nice one for playing morse code.
67+def mkwave(octave):
68+ global sinewave, nowave
69+ sinewave = ''
70+ for i in range(100):
71+ val = int(math.sin(math.pi * float(i) * octave / 50.0) * 30000)
72+ sinewave = sinewave + chr((val >> 8) & 255) + chr(val & 255)
73+ nowave = '\0' * 200
74+
75+mkwave(OCTAVE)
76+
77+def main():
78+ import getopt, string
79+ try:
80+ opts, args = getopt.getopt(sys.argv[1:], 'o:p:')
81+ except getopt.error:
82+ sys.stderr.write('Usage ' + sys.argv[0] +
83+ ' [ -o outfile ] [ args ] ...\n')
84+ sys.exit(1)
85+ dev = None
86+ for o, a in opts:
87+ if o == '-o':
88+ import aifc
89+ dev = aifc.open(a, 'w')
90+ dev.setframerate(44100)
91+ dev.setsampwidth(2)
92+ dev.setnchannels(1)
93+ if o == '-p':
94+ mkwave(string.atoi(a))
95+ if not dev:
96+ import audiodev
97+ dev = audiodev.AudioDev()
98+ dev.setoutrate(44100)
99+ dev.setsampwidth(2)
100+ dev.setnchannels(1)
101+ dev.close = dev.stop
102+ dev.writeframesraw = dev.writeframes
103+ if args:
104+ line = string.join(args)
105+ else:
106+ line = sys.stdin.readline()
107+ while line:
108+ mline = morse(line)
109+ play(mline, dev)
110+ if hasattr(dev, 'wait'):
111+ dev.wait()
112+ if not args:
113+ line = sys.stdin.readline()
114+ else:
115+ line = ''
116+ dev.close()
117+
118+# Convert a string to morse code with \001 between the characters in
119+# the string.
120+def morse(line):
121+ res = ''
122+ for c in line:
123+ try:
124+ res = res + morsetab[c] + '\001'
125+ except KeyError:
126+ pass
127+ return res
128+
129+# Play a line of morse code.
130+def play(line, dev):
131+ for c in line:
132+ if c == '.':
133+ sine(dev, DOT)
134+ elif c == '-':
135+ sine(dev, DAH)
136+ else: # space
137+ pause(dev, DAH + DOT)
138+ pause(dev, DOT)
139+
140+def sine(dev, length):
141+ for i in range(length):
142+ dev.writeframesraw(sinewave)
143+
144+def pause(dev, length):
145+ for i in range(length):
146+ dev.writeframesraw(nowave)
147+
148+if __name__ == '__main__' or sys.argv[0] == __name__:
149+ main()
sys/src/cmd/python/Demo/scripts/newslist.doc+59−0
@@ -0,0 +1,59 @@
1+ NEWSLIST
2+ ========
3+ A program to assist HTTP browsing of newsgroups
4+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5+
6+WWW browsers such as NCSA Mosaic allow the user to read newsgroup
7+articles by specifying the group name in a URL eg 'news:comp.answers'.
8+
9+To browse through many groups, though, (and there are several thousand
10+of them) you really need a page or pages containing links to all the
11+groups. There are some good ones out there, for example,
12+
13+ http://info.cern.ch/hypertext/DataSources/News/Groups/Overview.html
14+
15+is the standard one at CERN, but it only shows the groups available there,
16+which may be rather different from those available on your machine.
17+
18+Newslist is a program which creates a hierarchy of pages for you based
19+on the groups available from YOUR server. It is written in python - a
20+splendid interpreted object-oriented language which I suggest you get
21+right now from the directory /pub/python at ftp.cwi.nl, if you haven't
22+already got it.
23+
24+You should be able to see some sample output by looking at:
25+ http://pelican.cl.cam.ac.uk/newspage/root.html
26+
27+Descriptions of newsgroups can be added from a file with one group
28+per line. eg:
29+
30+ alt.foo Articles about foo
31+ comp.bar Programming in 'bar' and related languages
32+
33+A suitable list detailing most groups can be found at ftp.uu.net in
34+/uunet-info/newsgroups.gz.
35+
36+Make sure you read the information at the beginning of the program source and
37+configure the variables before running.
38+
39+In addition to python, you need:
40+
41+ An NNTP-based news feed.
42+ A directory in which to put the pages.
43+
44+The programming is not very beautiful, but it works! It comes with no
45+warranty, express or implied, but with the hope that some others may
46+find it useful.
47+
48+Comments, improvements & suggestions welcomed.
49+Quentin Stafford-Fraser
50+
51+ ----------------------------------------------------------------------
52+ Quentin Stafford-Fraser
53+ http://pelican.cl.cam.ac.uk/people/qs101/me.html
54+
55+ Cambridge University Computer Lab Rank Xerox Cambridge EuroPARC
56+ qs101@cl.cam.ac.uk fraser@europarc.xerox.com
57+ Tel: +44 223 334411 Tel: +44 223 341521
58+ Fax: +44 223 334679 Fax: +44 223 341510
59+ ----------------------------------------------------------------------
sys/src/cmd/python/Demo/scripts/newslist.py+366−0
@@ -0,0 +1,366 @@
1+#! /usr/bin/env python
2+#######################################################################
3+# Newslist $Revision: 37320 $
4+#
5+# Syntax:
6+# newslist [ -a ]
7+#
8+# This is a program to create a directory full of HTML pages
9+# which between them contain links to all the newsgroups available
10+# on your server.
11+#
12+# The -a option causes a complete list of all groups to be read from
13+# the server rather than just the ones which have appeared since last
14+# execution. This recreates the local list from scratch. Use this on
15+# the first invocation of the program, and from time to time thereafter.
16+# When new groups are first created they may appear on your server as
17+# empty groups. By default, empty groups are ignored by the -a option.
18+# However, these new groups will not be created again, and so will not
19+# appear in the server's list of 'new groups' at a later date. Hence it
20+# won't appear until you do a '-a' after some articles have appeared.
21+#
22+# I should really keep a list of ignored empty groups and re-check them
23+# for articles on every run, but I haven't got around to it yet.
24+#
25+# This assumes an NNTP news feed.
26+#
27+# Feel free to copy, distribute and modify this code for
28+# non-commercial use. If you make any useful modifications, let me
29+# know!
30+#
31+# (c) Quentin Stafford-Fraser 1994
32+# fraser@europarc.xerox.com qs101@cl.cam.ac.uk
33+# #
34+#######################################################################
35+import sys,nntplib, string, marshal, time, os, posix, string
36+
37+#######################################################################
38+# Check these variables before running! #
39+
40+# Top directory.
41+# Filenames which don't start with / are taken as being relative to this.
42+topdir='/anfs/qsbigdisc/web/html/newspage'
43+
44+# The name of your NNTP host
45+# eg.
46+# newshost = 'nntp-serv.cl.cam.ac.uk'
47+# or use following to get the name from the NNTPSERVER environment
48+# variable:
49+# newshost = posix.environ['NNTPSERVER']
50+newshost = 'nntp-serv.cl.cam.ac.uk'
51+
52+# The filename for a local cache of the newsgroup list
53+treefile = 'grouptree'
54+
55+# The filename for descriptions of newsgroups
56+# I found a suitable one at ftp.uu.net in /uunet-info/newgroups.gz
57+# You can set this to '' if you don't wish to use one.
58+descfile = 'newsgroups'
59+
60+# The directory in which HTML pages should be created
61+# eg.
62+# pagedir = '/usr/local/lib/html/newspage'
63+# pagedir = 'pages'
64+pagedir = topdir
65+
66+# The html prefix which will refer to this directory
67+# eg.
68+# httppref = '/newspage/',
69+# or leave blank for relative links between pages: (Recommended)
70+# httppref = ''
71+httppref = ''
72+
73+# The name of the 'root' news page in this directory.
74+# A .html suffix will be added.
75+rootpage = 'root'
76+
77+# Set skipempty to 0 if you wish to see links to empty groups as well.
78+# Only affects the -a option.
79+skipempty = 1
80+
81+# pagelinkicon can contain html to put an icon after links to
82+# further pages. This helps to make important links stand out.
83+# Set to '' if not wanted, or '...' is quite a good one.
84+pagelinkicon='... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> '
85+
86+# ---------------------------------------------------------------------
87+# Less important personal preferences:
88+
89+# Sublistsize controls the maximum number of items the will appear as
90+# an indented sub-list before the whole thing is moved onto a different
91+# page. The smaller this is, the more pages you will have, but the
92+# shorter each will be.
93+sublistsize = 4
94+
95+# That should be all. #
96+#######################################################################
97+
98+for dir in os.curdir, os.environ['HOME']:
99+ rcfile = os.path.join(dir, '.newslistrc.py')
100+ if os.path.exists(rcfile):
101+ print rcfile
102+ execfile(rcfile)
103+ break
104+
105+from nntplib import NNTP
106+from stat import *
107+
108+rcsrev = '$Revision: 37320 $'
109+rcsrev = string.join(filter(lambda s: '$' not in s, string.split(rcsrev)))
110+desc = {}
111+
112+# Make (possibly) relative filenames into absolute ones
113+treefile = os.path.join(topdir,treefile)
114+descfile = os.path.join(topdir,descfile)
115+page = os.path.join(topdir,pagedir)
116+
117+# First the bits for creating trees ---------------------------
118+
119+# Addtotree creates/augments a tree from a list of group names
120+def addtotree(tree, groups):
121+ print 'Updating tree...'
122+ for i in groups:
123+ parts = string.splitfields(i,'.')
124+ makeleaf(tree, parts)
125+
126+# Makeleaf makes a leaf and the branch leading to it if necessary
127+def makeleaf(tree,path):
128+ j = path[0]
129+ l = len(path)
130+
131+ if not tree.has_key(j):
132+ tree[j] = {}
133+ if l == 1:
134+ tree[j]['.'] = '.'
135+ if l > 1:
136+ makeleaf(tree[j],path[1:])
137+
138+# Then the bits for outputting trees as pages ----------------
139+
140+# Createpage creates an HTML file named <root>.html containing links
141+# to those groups beginning with <root>.
142+
143+def createpage(root, tree, p):
144+ filename = os.path.join(pagedir,root+'.html')
145+ if root == rootpage:
146+ detail = ''
147+ else:
148+ detail = ' under ' + root
149+ f = open(filename,'w')
150+ # f.write('Content-Type: text/html\n')
151+ f.write('<TITLE>Newsgroups available' + detail + '</TITLE>\n')
152+ f.write('<H1>Newsgroups available' + detail +'</H1>\n')
153+ f.write('<A HREF="'+httppref+rootpage+'.html">Back to top level</A><P>\n')
154+ printtree(f,tree,0,p)
155+ f.write('<I>This page automatically created by \'newslist\' v. '+rcsrev+'.')
156+ f.write(time.ctime(time.time()) + '</I><P>')
157+ f.close()
158+
159+# Printtree prints the groups as a bulleted list. Groups with
160+# more than <sublistsize> subgroups will be put on a separate page.
161+# Other sets of subgroups are just indented.
162+
163+def printtree(f, tree, indent, p):
164+ global desc
165+ l = len(tree)
166+
167+ if l > sublistsize and indent>0:
168+ # Create a new page and a link to it
169+ f.write('<LI><B><A HREF="'+httppref+p[1:]+'.html">')
170+ f.write(p[1:]+'.*')
171+ f.write('</A></B>'+pagelinkicon+'\n')
172+ createpage(p[1:], tree, p)
173+ return
174+
175+ kl = tree.keys()
176+
177+ if l > 1:
178+ kl.sort()
179+ if indent > 0:
180+ # Create a sub-list
181+ f.write('<LI>'+p[1:]+'\n<UL>')
182+ else:
183+ # Create a main list
184+ f.write('<UL>')
185+ indent = indent + 1
186+
187+ for i in kl:
188+ if i == '.':
189+ # Output a newsgroup
190+ f.write('<LI><A HREF="news:' + p[1:] + '">'+ p[1:] + '</A> ')
191+ if desc.has_key(p[1:]):
192+ f.write(' <I>'+desc[p[1:]]+'</I>\n')
193+ else:
194+ f.write('\n')
195+ else:
196+ # Output a hierarchy
197+ printtree(f,tree[i], indent, p+'.'+i)
198+
199+ if l > 1:
200+ f.write('\n</UL>')
201+
202+# Reading descriptions file ---------------------------------------
203+
204+# This returns an array mapping group name to its description
205+
206+def readdesc(descfile):
207+ global desc
208+
209+ desc = {}
210+
211+ if descfile == '':
212+ return
213+
214+ try:
215+ d = open(descfile, 'r')
216+ print 'Reading descriptions...'
217+ except (IOError):
218+ print 'Failed to open description file ' + descfile
219+ return
220+ l = d.readline()
221+ while l != '':
222+ bits = string.split(l)
223+ try:
224+ grp = bits[0]
225+ dsc = string.join(bits[1:])
226+ if len(dsc)>1:
227+ desc[grp] = dsc
228+ except (IndexError):
229+ pass
230+ l = d.readline()
231+
232+# Check that ouput directory exists, ------------------------------
233+# and offer to create it if not
234+
235+def checkopdir(pagedir):
236+ if not os.path.isdir(pagedir):
237+ print 'Directory '+pagedir+' does not exist.'
238+ print 'Shall I create it for you? (y/n)'
239+ if sys.stdin.readline()[0] == 'y':
240+ try:
241+ os.mkdir(pagedir,0777)
242+ except:
243+ print 'Sorry - failed!'
244+ sys.exit(1)
245+ else:
246+ print 'OK. Exiting.'
247+ sys.exit(1)
248+
249+# Read and write current local tree ----------------------------------
250+
251+def readlocallist(treefile):
252+ print 'Reading current local group list...'
253+ tree = {}
254+ try:
255+ treetime = time.localtime(os.stat(treefile)[ST_MTIME])
256+ except:
257+ print '\n*** Failed to open local group cache '+treefile
258+ print 'If this is the first time you have run newslist, then'
259+ print 'use the -a option to create it.'
260+ sys.exit(1)
261+ treedate = '%02d%02d%02d' % (treetime[0] % 100 ,treetime[1], treetime[2])
262+ try:
263+ dump = open(treefile,'r')
264+ tree = marshal.load(dump)
265+ dump.close()
266+ except (IOError):
267+ print 'Cannot open local group list ' + treefile
268+ return (tree, treedate)
269+
270+def writelocallist(treefile, tree):
271+ try:
272+ dump = open(treefile,'w')
273+ groups = marshal.dump(tree,dump)
274+ dump.close()
275+ print 'Saved list to '+treefile+'\n'
276+ except:
277+ print 'Sorry - failed to write to local group cache '+treefile
278+ print 'Does it (or its directory) have the correct permissions?'
279+ sys.exit(1)
280+
281+# Return list of all groups on server -----------------------------
282+
283+def getallgroups(server):
284+ print 'Getting list of all groups...'
285+ treedate='010101'
286+ info = server.list()[1]
287+ groups = []
288+ print 'Processing...'
289+ if skipempty:
290+ print '\nIgnoring following empty groups:'
291+ for i in info:
292+ grpname = string.split(i[0])[0]
293+ if skipempty and string.atoi(i[1]) < string.atoi(i[2]):
294+ print grpname+' ',
295+ else:
296+ groups.append(grpname)
297+ print '\n'
298+ if skipempty:
299+ print '(End of empty groups)'
300+ return groups
301+
302+# Return list of new groups on server -----------------------------
303+
304+def getnewgroups(server, treedate):
305+ print 'Getting list of new groups since start of '+treedate+'...',
306+ info = server.newgroups(treedate,'000001')[1]
307+ print 'got %d.' % len(info)
308+ print 'Processing...',
309+ groups = []
310+ for i in info:
311+ grpname = string.split(i)[0]
312+ groups.append(grpname)
313+ print 'Done'
314+ return groups
315+
316+# Now the main program --------------------------------------------
317+
318+def main():
319+ global desc
320+
321+ tree={}
322+
323+ # Check that the output directory exists
324+ checkopdir(pagedir);
325+
326+ try:
327+ print 'Connecting to '+newshost+'...'
328+ if sys.version[0] == '0':
329+ s = NNTP.init(newshost)
330+ else:
331+ s = NNTP(newshost)
332+ connected = 1
333+ except (nntplib.error_temp, nntplib.error_perm), x:
334+ print 'Error connecting to host:', x
335+ print 'I\'ll try to use just the local list.'
336+ connected = 0
337+
338+ # If -a is specified, read the full list of groups from server
339+ if connected and len(sys.argv) > 1 and sys.argv[1] == '-a':
340+
341+ groups = getallgroups(s)
342+
343+ # Otherwise just read the local file and then add
344+ # groups created since local file last modified.
345+ else:
346+
347+ (tree, treedate) = readlocallist(treefile)
348+ if connected:
349+ groups = getnewgroups(s, treedate)
350+
351+ if connected:
352+ addtotree(tree, groups)
353+ writelocallist(treefile,tree)
354+
355+ # Read group descriptions
356+ readdesc(descfile)
357+
358+ print 'Creating pages...'
359+ createpage(rootpage, tree, '')
360+ print 'Done'
361+
362+if __name__ == "__main__":
363+ main()
364+
365+# That's all folks
366+######################################################################
sys/src/cmd/python/Demo/scripts/pi.py+34−0
@@ -0,0 +1,34 @@
1+#! /usr/bin/env python
2+
3+# Print digits of pi forever.
4+#
5+# The algorithm, using Python's 'long' integers ("bignums"), works
6+# with continued fractions, and was conceived by Lambert Meertens.
7+#
8+# See also the ABC Programmer's Handbook, by Geurts, Meertens & Pemberton,
9+# published by Prentice-Hall (UK) Ltd., 1990.
10+
11+import sys
12+
13+def main():
14+ k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L
15+ while 1:
16+ # Next approximation
17+ p, q, k = k*k, 2L*k+1L, k+1L
18+ a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
19+ # Print common digits
20+ d, d1 = a/b, a1/b1
21+ while d == d1:
22+ output(d)
23+ a, a1 = 10L*(a%b), 10L*(a1%b1)
24+ d, d1 = a/b, a1/b1
25+
26+def output(d):
27+ # Use write() to avoid spaces between the digits
28+ # Use str() to avoid the 'L'
29+ sys.stdout.write(str(d))
30+ # Flush so the output is seen immediately
31+ sys.stdout.flush()
32+
33+if __name__ == "__main__":
34+ main()
sys/src/cmd/python/Demo/scripts/pp.py+130−0
@@ -0,0 +1,130 @@
1+#! /usr/bin/env python
2+
3+# Emulate some Perl command line options.
4+# Usage: pp [-a] [-c] [-d] [-e scriptline] [-F fieldsep] [-n] [-p] [file] ...
5+# Where the options mean the following:
6+# -a : together with -n or -p, splits each line into list F
7+# -c : check syntax only, do not execute any code
8+# -d : run the script under the debugger, pdb
9+# -e scriptline : gives one line of the Python script; may be repeated
10+# -F fieldsep : sets the field separator for the -a option [not in Perl]
11+# -n : runs the script for each line of input
12+# -p : prints the line after the script has run
13+# When no script lines have been passed, the first file argument
14+# contains the script. With -n or -p, the remaining arguments are
15+# read as input to the script, line by line. If a file is '-'
16+# or missing, standard input is read.
17+
18+# XXX To do:
19+# - add -i extension option (change files in place)
20+# - make a single loop over the files and lines (changes effect of 'break')?
21+# - add an option to specify the record separator
22+# - except for -n/-p, run directly from the file if at all possible
23+
24+import sys
25+import string
26+import getopt
27+
28+FS = ''
29+SCRIPT = []
30+AFLAG = 0
31+CFLAG = 0
32+DFLAG = 0
33+NFLAG = 0
34+PFLAG = 0
35+
36+try:
37+ optlist, ARGS = getopt.getopt(sys.argv[1:], 'acde:F:np')
38+except getopt.error, msg:
39+ sys.stderr.write(sys.argv[0] + ': ' + msg + '\n')
40+ sys.exit(2)
41+
42+for option, optarg in optlist:
43+ if option == '-a':
44+ AFLAG = 1
45+ elif option == '-c':
46+ CFLAG = 1
47+ elif option == '-d':
48+ DFLAG = 1
49+ elif option == '-e':
50+ for line in string.splitfields(optarg, '\n'):
51+ SCRIPT.append(line)
52+ elif option == '-F':
53+ FS = optarg
54+ elif option == '-n':
55+ NFLAG = 1
56+ PFLAG = 0
57+ elif option == '-p':
58+ NFLAG = 1
59+ PFLAG = 1
60+ else:
61+ print option, 'not recognized???'
62+
63+if not ARGS: ARGS.append('-')
64+
65+if not SCRIPT:
66+ if ARGS[0] == '-':
67+ fp = sys.stdin
68+ else:
69+ fp = open(ARGS[0], 'r')
70+ while 1:
71+ line = fp.readline()
72+ if not line: break
73+ SCRIPT.append(line[:-1])
74+ del fp
75+ del ARGS[0]
76+ if not ARGS: ARGS.append('-')
77+
78+if CFLAG:
79+ prologue = ['if 0:']
80+ epilogue = []
81+elif NFLAG:
82+ # Note that it is on purpose that AFLAG and PFLAG are
83+ # tested dynamically each time through the loop
84+ prologue = [ \
85+ 'LINECOUNT = 0', \
86+ 'for FILE in ARGS:', \
87+ ' \tif FILE == \'-\':', \
88+ ' \t \tFP = sys.stdin', \
89+ ' \telse:', \
90+ ' \t \tFP = open(FILE, \'r\')', \
91+ ' \tLINENO = 0', \
92+ ' \twhile 1:', \
93+ ' \t \tLINE = FP.readline()', \
94+ ' \t \tif not LINE: break', \
95+ ' \t \tLINENO = LINENO + 1', \
96+ ' \t \tLINECOUNT = LINECOUNT + 1', \
97+ ' \t \tL = LINE[:-1]', \
98+ ' \t \taflag = AFLAG', \
99+ ' \t \tif aflag:', \
100+ ' \t \t \tif FS: F = string.splitfields(L, FS)', \
101+ ' \t \t \telse: F = string.split(L)' \
102+ ]
103+ epilogue = [ \
104+ ' \t \tif not PFLAG: continue', \
105+ ' \t \tif aflag:', \
106+ ' \t \t \tif FS: print string.joinfields(F, FS)', \
107+ ' \t \t \telse: print string.join(F)', \
108+ ' \t \telse: print L', \
109+ ]
110+else:
111+ prologue = ['if 1:']
112+ epilogue = []
113+
114+# Note that we indent using tabs only, so that any indentation style
115+# used in 'command' will come out right after re-indentation.
116+
117+program = string.joinfields(prologue, '\n') + '\n'
118+for line in SCRIPT:
119+ program = program + (' \t \t' + line + '\n')
120+program = program + (string.joinfields(epilogue, '\n') + '\n')
121+
122+import tempfile
123+fp = tempfile.NamedTemporaryFile()
124+fp.write(program)
125+fp.flush()
126+if DFLAG:
127+ import pdb
128+ pdb.run('execfile(%r)' % (tfn,))
129+else:
130+ execfile(tfn)
sys/src/cmd/python/Demo/scripts/primes.py+27−0
@@ -0,0 +1,27 @@
1+#! /usr/bin/env python
2+
3+# Print prime numbers in a given range
4+
5+def main():
6+ import sys
7+ min, max = 2, 0x7fffffff
8+ if sys.argv[1:]:
9+ min = int(eval(sys.argv[1]))
10+ if sys.argv[2:]:
11+ max = int(eval(sys.argv[2]))
12+ primes(min, max)
13+
14+def primes(min, max):
15+ if 2 >= min: print 2
16+ primes = [2]
17+ i = 3
18+ while i <= max:
19+ for p in primes:
20+ if i%p == 0 or p*p > i: break
21+ if i%p <> 0:
22+ primes.append(i)
23+ if i >= min: print i
24+ i = i+2
25+
26+if __name__ == "__main__":
27+ main()
sys/src/cmd/python/Demo/scripts/queens.py+85−0
@@ -0,0 +1,85 @@
1+#! /usr/bin/env python
2+
3+"""N queens problem.
4+
5+The (well-known) problem is due to Niklaus Wirth.
6+
7+This solution is inspired by Dijkstra (Structured Programming). It is
8+a classic recursive backtracking approach.
9+
10+"""
11+
12+N = 8 # Default; command line overrides
13+
14+class Queens:
15+
16+ def __init__(self, n=N):
17+ self.n = n
18+ self.reset()
19+
20+ def reset(self):
21+ n = self.n
22+ self.y = [None]*n # Where is the queen in column x
23+ self.row = [0]*n # Is row[y] safe?
24+ self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe?
25+ self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe?
26+ self.nfound = 0 # Instrumentation
27+
28+ def solve(self, x=0): # Recursive solver
29+ for y in range(self.n):
30+ if self.safe(x, y):
31+ self.place(x, y)
32+ if x+1 == self.n:
33+ self.display()
34+ else:
35+ self.solve(x+1)
36+ self.remove(x, y)
37+
38+ def safe(self, x, y):
39+ return not self.row[y] and not self.up[x-y] and not self.down[x+y]
40+
41+ def place(self, x, y):
42+ self.y[x] = y
43+ self.row[y] = 1
44+ self.up[x-y] = 1
45+ self.down[x+y] = 1
46+
47+ def remove(self, x, y):
48+ self.y[x] = None
49+ self.row[y] = 0
50+ self.up[x-y] = 0
51+ self.down[x+y] = 0
52+
53+ silent = 0 # If set, count solutions only
54+
55+ def display(self):
56+ self.nfound = self.nfound + 1
57+ if self.silent:
58+ return
59+ print '+-' + '--'*self.n + '+'
60+ for y in range(self.n-1, -1, -1):
61+ print '|',
62+ for x in range(self.n):
63+ if self.y[x] == y:
64+ print "Q",
65+ else:
66+ print ".",
67+ print '|'
68+ print '+-' + '--'*self.n + '+'
69+
70+def main():
71+ import sys
72+ silent = 0
73+ n = N
74+ if sys.argv[1:2] == ['-n']:
75+ silent = 1
76+ del sys.argv[1]
77+ if sys.argv[1:]:
78+ n = int(sys.argv[1])
79+ q = Queens(n)
80+ q.silent = silent
81+ q.solve()
82+ print "Found", q.nfound, "solutions."
83+
84+if __name__ == "__main__":
85+ main()
sys/src/cmd/python/Demo/scripts/script.py+33−0
@@ -0,0 +1,33 @@
1+#! /usr/bin/env python
2+# script.py -- Make typescript of terminal session.
3+# Usage:
4+# -a Append to typescript.
5+# -p Use Python as shell.
6+# Author: Steen Lumholt.
7+
8+
9+import os, time, sys
10+import pty
11+
12+def read(fd):
13+ data = os.read(fd, 1024)
14+ file.write(data)
15+ return data
16+
17+shell = 'sh'
18+filename = 'typescript'
19+mode = 'w'
20+if os.environ.has_key('SHELL'):
21+ shell = os.environ['SHELL']
22+if '-a' in sys.argv:
23+ mode = 'a'
24+if '-p' in sys.argv:
25+ shell = 'python'
26+
27+file = open(filename, mode)
28+
29+sys.stdout.write('Script started, file is %s\n' % filename)
30+file.write('Script started on %s\n' % time.ctime(time.time()))
31+pty.spawn(shell, read)
32+file.write('Script done on %s\n' % time.ctime(time.time()))
33+sys.stdout.write('Script done, file is %s\n' % filename)
sys/src/cmd/python/Demo/scripts/unbirthday.py+107−0
@@ -0,0 +1,107 @@
1+#! /usr/bin/env python
2+
3+# Calculate your unbirthday count (see Alice in Wonderland).
4+# This is defined as the number of days from your birth until today
5+# that weren't your birthday. (The day you were born is not counted).
6+# Leap years make it interesting.
7+
8+import sys
9+import time
10+import calendar
11+
12+def main():
13+ # Note that the range checks below also check for bad types,
14+ # e.g. 3.14 or (). However syntactically invalid replies
15+ # will raise an exception.
16+ if sys.argv[1:]:
17+ year = int(sys.argv[1])
18+ else:
19+ year = int(raw_input('In which year were you born? '))
20+ if 0<=year<100:
21+ print "I'll assume that by", year,
22+ year = year + 1900
23+ print 'you mean', year, 'and not the early Christian era'
24+ elif not (1850<=year<=2002):
25+ print "It's hard to believe you were born in", year
26+ return
27+ #
28+ if sys.argv[2:]:
29+ month = int(sys.argv[2])
30+ else:
31+ month = int(raw_input('And in which month? (1-12) '))
32+ if not (1<=month<=12):
33+ print 'There is no month numbered', month
34+ return
35+ #
36+ if sys.argv[3:]:
37+ day = int(sys.argv[3])
38+ else:
39+ day = int(raw_input('And on what day of that month? (1-31) '))
40+ if month == 2 and calendar.isleap(year):
41+ maxday = 29
42+ else:
43+ maxday = calendar.mdays[month]
44+ if not (1<=day<=maxday):
45+ print 'There are no', day, 'days in that month!'
46+ return
47+ #
48+ bdaytuple = (year, month, day)
49+ bdaydate = mkdate(bdaytuple)
50+ print 'You were born on', format(bdaytuple)
51+ #
52+ todaytuple = time.localtime()[:3]
53+ todaydate = mkdate(todaytuple)
54+ print 'Today is', format(todaytuple)
55+ #
56+ if bdaytuple > todaytuple:
57+ print 'You are a time traveler. Go back to the future!'
58+ return
59+ #
60+ if bdaytuple == todaytuple:
61+ print 'You were born today. Have a nice life!'
62+ return
63+ #
64+ days = todaydate - bdaydate
65+ print 'You have lived', days, 'days'
66+ #
67+ age = 0
68+ for y in range(year, todaytuple[0] + 1):
69+ if bdaytuple < (y, month, day) <= todaytuple:
70+ age = age + 1
71+ #
72+ print 'You are', age, 'years old'
73+ #
74+ if todaytuple[1:] == bdaytuple[1:]:
75+ print 'Congratulations! Today is your', nth(age), 'birthday'
76+ print 'Yesterday was your',
77+ else:
78+ print 'Today is your',
79+ print nth(days - age), 'unbirthday'
80+
81+def format((year, month, day)):
82+ return '%d %s %d' % (day, calendar.month_name[month], year)
83+
84+def nth(n):
85+ if n == 1: return '1st'
86+ if n == 2: return '2nd'
87+ if n == 3: return '3rd'
88+ return '%dth' % n
89+
90+def mkdate((year, month, day)):
91+ # Januari 1st, in 0 A.D. is arbitrarily defined to be day 1,
92+ # even though that day never actually existed and the calendar
93+ # was different then...
94+ days = year*365 # years, roughly
95+ days = days + (year+3)/4 # plus leap years, roughly
96+ days = days - (year+99)/100 # minus non-leap years every century
97+ days = days + (year+399)/400 # plus leap years every 4 centirues
98+ for i in range(1, month):
99+ if i == 2 and calendar.isleap(year):
100+ days = days + 29
101+ else:
102+ days = days + calendar.mdays[i]
103+ days = days + day
104+ return days
105+
106+if __name__ == "__main__":
107+ main()
sys/src/cmd/python/Demo/scripts/update.py+92−0
@@ -0,0 +1,92 @@
1+#! /usr/bin/env python
2+
3+# Update a bunch of files according to a script.
4+# The input file contains lines of the form <filename>:<lineno>:<text>,
5+# meaning that the given line of the given file is to be replaced
6+# by the given text. This is useful for performing global substitutions
7+# on grep output:
8+
9+import os
10+import sys
11+import re
12+
13+pat = '^([^: \t\n]+):([1-9][0-9]*):'
14+prog = re.compile(pat)
15+
16+class FileObj:
17+ def __init__(self, filename):
18+ self.filename = filename
19+ self.changed = 0
20+ try:
21+ self.lines = open(filename, 'r').readlines()
22+ except IOError, msg:
23+ print '*** Can\'t open "%s":' % filename, msg
24+ self.lines = None
25+ return
26+ print 'diffing', self.filename
27+
28+ def finish(self):
29+ if not self.changed:
30+ print 'no changes to', self.filename
31+ return
32+ try:
33+ os.rename(self.filename, self.filename + '~')
34+ fp = open(self.filename, 'w')
35+ except (os.error, IOError), msg:
36+ print '*** Can\'t rewrite "%s":' % self.filename, msg
37+ return
38+ print 'writing', self.filename
39+ for line in self.lines:
40+ fp.write(line)
41+ fp.close()
42+ self.changed = 0
43+
44+ def process(self, lineno, rest):
45+ if self.lines is None:
46+ print '(not processed): %s:%s:%s' % (
47+ self.filename, lineno, rest),
48+ return
49+ i = eval(lineno) - 1
50+ if not 0 <= i < len(self.lines):
51+ print '*** Line number out of range: %s:%s:%s' % (
52+ self.filename, lineno, rest),
53+ return
54+ if self.lines[i] == rest:
55+ print '(no change): %s:%s:%s' % (
56+ self.filename, lineno, rest),
57+ return
58+ if not self.changed:
59+ self.changed = 1
60+ print '%sc%s' % (lineno, lineno)
61+ print '<', self.lines[i],
62+ print '---'
63+ self.lines[i] = rest
64+ print '>', self.lines[i],
65+
66+def main():
67+ if sys.argv[1:]:
68+ try:
69+ fp = open(sys.argv[1], 'r')
70+ except IOError, msg:
71+ print 'Can\'t open "%s":' % sys.argv[1], msg
72+ sys.exit(1)
73+ else:
74+ fp = sys.stdin
75+ curfile = None
76+ while 1:
77+ line = fp.readline()
78+ if not line:
79+ if curfile: curfile.finish()
80+ break
81+ n = prog.match(line)
82+ if n < 0:
83+ print 'Funny line:', line,
84+ continue
85+ filename, lineno = prog.group(1, 2)
86+ if not curfile or filename <> curfile.filename:
87+ if curfile: curfile.finish()
88+ curfile = FileObj(filename)
89+ curfile.process(lineno, line[n:])
90+
91+if __name__ == "__main__":
92+ main()
sys/src/cmd/python/Demo/scripts/wh.py+2−0
@@ -0,0 +1,2 @@
1+# This is here so I can use 'wh' instead of 'which' in '~/bin/generic_python'
2+import which
sys/src/cmd/python/Demo/sockets/README+21−0
@@ -0,0 +1,21 @@
1+This directory contains some demonstrations of the socket module:
2+
3+broadcast.py Broadcast the time to radio.py.
4+echosvr.py About the simplest TCP server possible.
5+finger.py Client for the 'finger' protocol.
6+ftp.py A very simple ftp client.
7+gopher.py A simple gopher client.
8+radio.py Receive time broadcasts from broadcast.py.
9+telnet.py Client for the 'telnet' protocol.
10+throughput.py Client and server to measure TCP throughput.
11+unixclient.py Unix socket example, client side
12+unixserver.py Unix socket example, server side
13+udpecho.py Client and server for the UDP echo protocol.
14+
15+The following file is only relevant on SGI machines (or other systems
16+that support multicast):
17+
18+mcast.py A Python translation of
19+ /usr/people/4Dgifts/examples/network/mcast.c
20+ (Note that IN.py is in ../../lib/sgi.)
21+
sys/src/cmd/python/Demo/sockets/broadcast.py+15−0
@@ -0,0 +1,15 @@
1+# Send UDP broadcast packets
2+
3+MYPORT = 50000
4+
5+import sys, time
6+from socket import *
7+
8+s = socket(AF_INET, SOCK_DGRAM)
9+s.bind(('', 0))
10+s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
11+
12+while 1:
13+ data = repr(time.time()) + '\n'
14+ s.sendto(data, ('<broadcast>', MYPORT))
15+ time.sleep(2)
sys/src/cmd/python/Demo/sockets/echosvr.py+31−0
@@ -0,0 +1,31 @@
1+#! /usr/bin/env python
2+
3+# Python implementation of an 'echo' tcp server: echo all data it receives.
4+#
5+# This is the simplest possible server, servicing a single request only.
6+
7+import sys
8+from socket import *
9+
10+# The standard echo port isn't very useful, it requires root permissions!
11+# ECHO_PORT = 7
12+ECHO_PORT = 50000 + 7
13+BUFSIZE = 1024
14+
15+def main():
16+ if len(sys.argv) > 1:
17+ port = int(eval(sys.argv[1]))
18+ else:
19+ port = ECHO_PORT
20+ s = socket(AF_INET, SOCK_STREAM)
21+ s.bind(('', port))
22+ s.listen(1)
23+ conn, (remotehost, remoteport) = s.accept()
24+ print 'connected by', remotehost, remoteport
25+ while 1:
26+ data = conn.recv(BUFSIZE)
27+ if not data:
28+ break
29+ conn.send(data)
30+
31+main()
sys/src/cmd/python/Demo/sockets/finger.py+58−0
@@ -0,0 +1,58 @@
1+#! /usr/bin/env python
2+
3+# Python interface to the Internet finger daemon.
4+#
5+# Usage: finger [options] [user][@host] ...
6+#
7+# If no host is given, the finger daemon on the local host is contacted.
8+# Options are passed uninterpreted to the finger daemon!
9+
10+
11+import sys, string
12+from socket import *
13+
14+
15+# Hardcode the number of the finger port here.
16+# It's not likely to change soon...
17+#
18+FINGER_PORT = 79
19+
20+
21+# Function to do one remote finger invocation.
22+# Output goes directly to stdout (although this can be changed).
23+#
24+def finger(host, args):
25+ s = socket(AF_INET, SOCK_STREAM)
26+ s.connect((host, FINGER_PORT))
27+ s.send(args + '\n')
28+ while 1:
29+ buf = s.recv(1024)
30+ if not buf: break
31+ sys.stdout.write(buf)
32+ sys.stdout.flush()
33+
34+
35+# Main function: argument parsing.
36+#
37+def main():
38+ options = ''
39+ i = 1
40+ while i < len(sys.argv) and sys.argv[i][:1] == '-':
41+ options = options + sys.argv[i] + ' '
42+ i = i+1
43+ args = sys.argv[i:]
44+ if not args:
45+ args = ['']
46+ for arg in args:
47+ if '@' in arg:
48+ at = string.index(arg, '@')
49+ host = arg[at+1:]
50+ arg = arg[:at]
51+ else:
52+ host = ''
53+ finger(host, options + arg)
54+
55+
56+# Call the main function.
57+#
58+main()
sys/src/cmd/python/Demo/sockets/ftp.py+146−0
@@ -0,0 +1,146 @@
1+# A simple FTP client.
2+#
3+# The information to write this program was gathered from RFC 959,
4+# but this is not a complete implementation! Yet it shows how a simple
5+# FTP client can be built, and you are welcome to extend it to suit
6+# it to your needs...
7+#
8+# How it works (assuming you've read the RFC):
9+#
10+# User commands are passed uninterpreted to the server. However, the
11+# user never needs to send a PORT command. Rather, the client opens a
12+# port right away and sends the appropriate PORT command to the server.
13+# When a response code 150 is received, this port is used to receive
14+# the data (which is written to stdout in this version), and when the
15+# data is exhausted, a new port is opened and a corresponding PORT
16+# command sent. In order to avoid errors when reusing ports quickly
17+# (and because there is no s.getsockname() method in Python yet) we
18+# cycle through a number of ports in the 50000 range.
19+
20+
21+import sys, posix, string
22+from socket import *
23+
24+
25+BUFSIZE = 1024
26+
27+# Default port numbers used by the FTP protocol.
28+#
29+FTP_PORT = 21
30+FTP_DATA_PORT = FTP_PORT - 1
31+
32+# Change the data port to something not needing root permissions.
33+#
34+FTP_DATA_PORT = FTP_DATA_PORT + 50000
35+
36+
37+# Main program (called at the end of this file).
38+#
39+def main():
40+ hostname = sys.argv[1]
41+ control(hostname)
42+
43+
44+# Control process (user interface and user protocol interpreter).
45+#
46+def control(hostname):
47+ #
48+ # Create control connection
49+ #
50+ s = socket(AF_INET, SOCK_STREAM)
51+ s.connect((hostname, FTP_PORT))
52+ f = s.makefile('r') # Reading the replies is easier from a file...
53+ #
54+ # Control loop
55+ #
56+ r = None
57+ while 1:
58+ code = getreply(f)
59+ if code in ('221', 'EOF'): break
60+ if code == '150':
61+ getdata(r)
62+ code = getreply(f)
63+ r = None
64+ if not r:
65+ r = newdataport(s, f)
66+ cmd = getcommand()
67+ if not cmd: break
68+ s.send(cmd + '\r\n')
69+
70+
71+# Create a new data port and send a PORT command to the server for it.
72+# (Cycle through a number of ports to avoid problems with reusing
73+# a port within a short time.)
74+#
75+nextport = 0
76+#
77+def newdataport(s, f):
78+ global nextport
79+ port = nextport + FTP_DATA_PORT
80+ nextport = (nextport+1) % 16
81+ r = socket(AF_INET, SOCK_STREAM)
82+ r.bind((gethostbyname(gethostname()), port))
83+ r.listen(1)
84+ sendportcmd(s, f, port)
85+ return r
86+
87+
88+# Send an appropriate port command.
89+#
90+def sendportcmd(s, f, port):
91+ hostname = gethostname()
92+ hostaddr = gethostbyname(hostname)
93+ hbytes = string.splitfields(hostaddr, '.')
94+ pbytes = [repr(port/256), repr(port%256)]
95+ bytes = hbytes + pbytes
96+ cmd = 'PORT ' + string.joinfields(bytes, ',')
97+ s.send(cmd + '\r\n')
98+ code = getreply(f)
99+
100+
101+# Process an ftp reply and return the 3-digit reply code (as a string).
102+# The reply should be a line of text starting with a 3-digit number.
103+# If the 4th char is '-', it is a multi-line reply and is
104+# terminate by a line starting with the same 3-digit number.
105+# Any text while receiving the reply is echoed to the file.
106+#
107+def getreply(f):
108+ line = f.readline()
109+ if not line: return 'EOF'
110+ print line,
111+ code = line[:3]
112+ if line[3:4] == '-':
113+ while 1:
114+ line = f.readline()
115+ if not line: break # Really an error
116+ print line,
117+ if line[:3] == code and line[3:4] != '-': break
118+ return code
119+
120+
121+# Get the data from the data connection.
122+#
123+def getdata(r):
124+ print '(accepting data connection)'
125+ conn, host = r.accept()
126+ print '(data connection accepted)'
127+ while 1:
128+ data = conn.recv(BUFSIZE)
129+ if not data: break
130+ sys.stdout.write(data)
131+ print '(end of data connection)'
132+
133+# Get a command from the user.
134+#
135+def getcommand():
136+ try:
137+ while 1:
138+ line = raw_input('ftp.py> ')
139+ if line: return line
140+ except EOFError:
141+ return ''
142+
143+
144+# Call the main program.
145+#
146+main()
sys/src/cmd/python/Demo/sockets/gopher.py+347−0
@@ -0,0 +1,347 @@
1+#! /usr/bin/env python
2+
3+# A simple gopher client.
4+#
5+# Usage: gopher [ [selector] host [port] ]
6+
7+import string
8+import sys
9+import os
10+import socket
11+
12+# Default selector, host and port
13+DEF_SELECTOR = ''
14+DEF_HOST = 'gopher.micro.umn.edu'
15+DEF_PORT = 70
16+
17+# Recognized file types
18+T_TEXTFILE = '0'
19+T_MENU = '1'
20+T_CSO = '2'
21+T_ERROR = '3'
22+T_BINHEX = '4'
23+T_DOS = '5'
24+T_UUENCODE = '6'
25+T_SEARCH = '7'
26+T_TELNET = '8'
27+T_BINARY = '9'
28+T_REDUNDANT = '+'
29+T_SOUND = 's'
30+
31+# Dictionary mapping types to strings
32+typename = {'0': '<TEXT>', '1': '<DIR>', '2': '<CSO>', '3': '<ERROR>', \
33+ '4': '<BINHEX>', '5': '<DOS>', '6': '<UUENCODE>', '7': '<SEARCH>', \
34+ '8': '<TELNET>', '9': '<BINARY>', '+': '<REDUNDANT>', 's': '<SOUND>'}
35+
36+# Oft-used characters and strings
37+CRLF = '\r\n'
38+TAB = '\t'
39+
40+# Open a TCP connection to a given host and port
41+def open_socket(host, port):
42+ if not port:
43+ port = DEF_PORT
44+ elif type(port) == type(''):
45+ port = string.atoi(port)
46+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
47+ s.connect((host, port))
48+ return s
49+
50+# Send a selector to a given host and port, return a file with the reply
51+def send_request(selector, host, port):
52+ s = open_socket(host, port)
53+ s.send(selector + CRLF)
54+ s.shutdown(1)
55+ return s.makefile('r')
56+
57+# Get a menu in the form of a list of entries
58+def get_menu(selector, host, port):
59+ f = send_request(selector, host, port)
60+ list = []
61+ while 1:
62+ line = f.readline()
63+ if not line:
64+ print '(Unexpected EOF from server)'
65+ break
66+ if line[-2:] == CRLF:
67+ line = line[:-2]
68+ elif line[-1:] in CRLF:
69+ line = line[:-1]
70+ if line == '.':
71+ break
72+ if not line:
73+ print '(Empty line from server)'
74+ continue
75+ typechar = line[0]
76+ parts = string.splitfields(line[1:], TAB)
77+ if len(parts) < 4:
78+ print '(Bad line from server: %r)' % (line,)
79+ continue
80+ if len(parts) > 4:
81+ print '(Extra info from server: %r)' % (parts[4:],)
82+ parts.insert(0, typechar)
83+ list.append(parts)
84+ f.close()
85+ return list
86+
87+# Get a text file as a list of lines, with trailing CRLF stripped
88+def get_textfile(selector, host, port):
89+ list = []
90+ get_alt_textfile(selector, host, port, list.append)
91+ return list
92+
93+# Get a text file and pass each line to a function, with trailing CRLF stripped
94+def get_alt_textfile(selector, host, port, func):
95+ f = send_request(selector, host, port)
96+ while 1:
97+ line = f.readline()
98+ if not line:
99+ print '(Unexpected EOF from server)'
100+ break
101+ if line[-2:] == CRLF:
102+ line = line[:-2]
103+ elif line[-1:] in CRLF:
104+ line = line[:-1]
105+ if line == '.':
106+ break
107+ if line[:2] == '..':
108+ line = line[1:]
109+ func(line)
110+ f.close()
111+
112+# Get a binary file as one solid data block
113+def get_binary(selector, host, port):
114+ f = send_request(selector, host, port)
115+ data = f.read()
116+ f.close()
117+ return data
118+
119+# Get a binary file and pass each block to a function
120+def get_alt_binary(selector, host, port, func, blocksize):
121+ f = send_request(selector, host, port)
122+ while 1:
123+ data = f.read(blocksize)
124+ if not data:
125+ break
126+ func(data)
127+
128+# A *very* simple interactive browser
129+
130+# Browser main command, has default arguments
131+def browser(*args):
132+ selector = DEF_SELECTOR
133+ host = DEF_HOST
134+ port = DEF_PORT
135+ n = len(args)
136+ if n > 0 and args[0]:
137+ selector = args[0]
138+ if n > 1 and args[1]:
139+ host = args[1]
140+ if n > 2 and args[2]:
141+ port = args[2]
142+ if n > 3:
143+ raise RuntimeError, 'too many args'
144+ try:
145+ browse_menu(selector, host, port)
146+ except socket.error, msg:
147+ print 'Socket error:', msg
148+ sys.exit(1)
149+ except KeyboardInterrupt:
150+ print '\n[Goodbye]'
151+
152+# Browse a menu
153+def browse_menu(selector, host, port):
154+ list = get_menu(selector, host, port)
155+ while 1:
156+ print '----- MENU -----'
157+ print 'Selector:', repr(selector)
158+ print 'Host:', host, ' Port:', port
159+ print
160+ for i in range(len(list)):
161+ item = list[i]
162+ typechar, description = item[0], item[1]
163+ print string.rjust(repr(i+1), 3) + ':', description,
164+ if typename.has_key(typechar):
165+ print typename[typechar]
166+ else:
167+ print '<TYPE=' + repr(typechar) + '>'
168+ print
169+ while 1:
170+ try:
171+ str = raw_input('Choice [CR == up a level]: ')
172+ except EOFError:
173+ print
174+ return
175+ if not str:
176+ return
177+ try:
178+ choice = string.atoi(str)
179+ except string.atoi_error:
180+ print 'Choice must be a number; try again:'
181+ continue
182+ if not 0 < choice <= len(list):
183+ print 'Choice out of range; try again:'
184+ continue
185+ break
186+ item = list[choice-1]
187+ typechar = item[0]
188+ [i_selector, i_host, i_port] = item[2:5]
189+ if typebrowser.has_key(typechar):
190+ browserfunc = typebrowser[typechar]
191+ try:
192+ browserfunc(i_selector, i_host, i_port)
193+ except (IOError, socket.error):
194+ print '***', sys.exc_type, ':', sys.exc_value
195+ else:
196+ print 'Unsupported object type'
197+
198+# Browse a text file
199+def browse_textfile(selector, host, port):
200+ x = None
201+ try:
202+ p = os.popen('${PAGER-more}', 'w')
203+ x = SaveLines(p)
204+ get_alt_textfile(selector, host, port, x.writeln)
205+ except IOError, msg:
206+ print 'IOError:', msg
207+ if x:
208+ x.close()
209+ f = open_savefile()
210+ if not f:
211+ return
212+ x = SaveLines(f)
213+ try:
214+ get_alt_textfile(selector, host, port, x.writeln)
215+ print 'Done.'
216+ except IOError, msg:
217+ print 'IOError:', msg
218+ x.close()
219+
220+# Browse a search index
221+def browse_search(selector, host, port):
222+ while 1:
223+ print '----- SEARCH -----'
224+ print 'Selector:', repr(selector)
225+ print 'Host:', host, ' Port:', port
226+ print
227+ try:
228+ query = raw_input('Query [CR == up a level]: ')
229+ except EOFError:
230+ print
231+ break
232+ query = string.strip(query)
233+ if not query:
234+ break
235+ if '\t' in query:
236+ print 'Sorry, queries cannot contain tabs'
237+ continue
238+ browse_menu(selector + TAB + query, host, port)
239+
240+# "Browse" telnet-based information, i.e. open a telnet session
241+def browse_telnet(selector, host, port):
242+ if selector:
243+ print 'Log in as', repr(selector)
244+ if type(port) <> type(''):
245+ port = repr(port)
246+ sts = os.system('set -x; exec telnet ' + host + ' ' + port)
247+ if sts:
248+ print 'Exit status:', sts
249+
250+# "Browse" a binary file, i.e. save it to a file
251+def browse_binary(selector, host, port):
252+ f = open_savefile()
253+ if not f:
254+ return
255+ x = SaveWithProgress(f)
256+ get_alt_binary(selector, host, port, x.write, 8*1024)
257+ x.close()
258+
259+# "Browse" a sound file, i.e. play it or save it
260+def browse_sound(selector, host, port):
261+ browse_binary(selector, host, port)
262+
263+# Dictionary mapping types to browser functions
264+typebrowser = {'0': browse_textfile, '1': browse_menu, \
265+ '4': browse_binary, '5': browse_binary, '6': browse_textfile, \
266+ '7': browse_search, \
267+ '8': browse_telnet, '9': browse_binary, 's': browse_sound}
268+
269+# Class used to save lines, appending a newline to each line
270+class SaveLines:
271+ def __init__(self, f):
272+ self.f = f
273+ def writeln(self, line):
274+ self.f.write(line + '\n')
275+ def close(self):
276+ sts = self.f.close()
277+ if sts:
278+ print 'Exit status:', sts
279+
280+# Class used to save data while showing progress
281+class SaveWithProgress:
282+ def __init__(self, f):
283+ self.f = f
284+ def write(self, data):
285+ sys.stdout.write('#')
286+ sys.stdout.flush()
287+ self.f.write(data)
288+ def close(self):
289+ print
290+ sts = self.f.close()
291+ if sts:
292+ print 'Exit status:', sts
293+
294+# Ask for and open a save file, or return None if not to save
295+def open_savefile():
296+ try:
297+ savefile = raw_input( \
298+ 'Save as file [CR == don\'t save; |pipeline or ~user/... OK]: ')
299+ except EOFError:
300+ print
301+ return None
302+ savefile = string.strip(savefile)
303+ if not savefile:
304+ return None
305+ if savefile[0] == '|':
306+ cmd = string.strip(savefile[1:])
307+ try:
308+ p = os.popen(cmd, 'w')
309+ except IOError, msg:
310+ print repr(cmd), ':', msg
311+ return None
312+ print 'Piping through', repr(cmd), '...'
313+ return p
314+ if savefile[0] == '~':
315+ savefile = os.path.expanduser(savefile)
316+ try:
317+ f = open(savefile, 'w')
318+ except IOError, msg:
319+ print repr(savefile), ':', msg
320+ return None
321+ print 'Saving to', repr(savefile), '...'
322+ return f
323+
324+# Test program
325+def test():
326+ if sys.argv[4:]:
327+ print 'usage: gopher [ [selector] host [port] ]'
328+ sys.exit(2)
329+ elif sys.argv[3:]:
330+ browser(sys.argv[1], sys.argv[2], sys.argv[3])
331+ elif sys.argv[2:]:
332+ try:
333+ port = string.atoi(sys.argv[2])
334+ selector = ''
335+ host = sys.argv[1]
336+ except string.atoi_error:
337+ selector = sys.argv[1]
338+ host = sys.argv[2]
339+ port = ''
340+ browser(selector, host, port)
341+ elif sys.argv[1:]:
342+ browser('', sys.argv[1])
343+ else:
344+ browser()
345+
346+# Call the test program as a main program
347+test()
sys/src/cmd/python/Demo/sockets/mcast.py+93−0
@@ -0,0 +1,93 @@
1+# Send/receive UDP multicast packets.
2+# Requires that your OS kernel supports IP multicast.
3+# This is built-in on SGI, still optional for most other vendors.
4+#
5+# Usage:
6+# mcast -s (sender)
7+# mcast -b (sender, using broadcast instead multicast)
8+# mcast (receivers)
9+
10+MYPORT = 8123
11+MYGROUP = '225.0.0.250'
12+
13+import sys
14+import time
15+import struct
16+from socket import *
17+
18+
19+# Main program
20+def main():
21+ flags = sys.argv[1:]
22+ #
23+ if flags:
24+ sender(flags[0])
25+ else:
26+ receiver()
27+
28+
29+# Sender subroutine (only one per local area network)
30+def sender(flag):
31+ s = socket(AF_INET, SOCK_DGRAM)
32+ if flag == '-b':
33+ s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
34+ mygroup = '<broadcast>'
35+ else:
36+ mygroup = MYGROUP
37+ ttl = struct.pack('b', 1) # Time-to-live
38+ s.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, ttl)
39+ while 1:
40+ data = repr(time.time())
41+## data = data + (1400 - len(data)) * '\0'
42+ s.sendto(data, (mygroup, MYPORT))
43+ time.sleep(1)
44+
45+
46+# Receiver subroutine (as many as you like)
47+def receiver():
48+ # Open and initialize the socket
49+ s = openmcastsock(MYGROUP, MYPORT)
50+ #
51+ # Loop, printing any data we receive
52+ while 1:
53+ data, sender = s.recvfrom(1500)
54+ while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's
55+ print sender, ':', repr(data)
56+
57+
58+# Open a UDP socket, bind it to a port and select a multicast group
59+def openmcastsock(group, port):
60+ # Import modules used only here
61+ import string
62+ import struct
63+ #
64+ # Create a socket
65+ s = socket(AF_INET, SOCK_DGRAM)
66+ #
67+ # Allow multiple copies of this program on one machine
68+ # (not strictly needed)
69+ s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
70+ #
71+ # Bind it to the port
72+ s.bind(('', port))
73+ #
74+ # Look up multicast group address in name server
75+ # (doesn't hurt if it is already in ddd.ddd.ddd.ddd format)
76+ group = gethostbyname(group)
77+ #
78+ # Construct binary group address
79+ bytes = map(int, string.split(group, "."))
80+ grpaddr = 0
81+ for byte in bytes: grpaddr = (grpaddr << 8) | byte
82+ #
83+ # Construct struct mreq from grpaddr and ifaddr
84+ ifaddr = INADDR_ANY
85+ mreq = struct.pack('ll', htonl(grpaddr), htonl(ifaddr))
86+ #
87+ # Add group membership
88+ s.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq)
89+ #
90+ return s
91+
92+
93+main()
sys/src/cmd/python/Demo/sockets/radio.py+14−0
@@ -0,0 +1,14 @@
1+# Receive UDP packets transmitted by a broadcasting service
2+
3+MYPORT = 50000
4+
5+import sys
6+from socket import *
7+
8+s = socket(AF_INET, SOCK_DGRAM)
9+s.bind(('', MYPORT))
10+
11+while 1:
12+ data, wherefrom = s.recvfrom(1500, 0)
13+ sys.stderr.write(repr(wherefrom) + '\n')
14+ sys.stdout.write(data)
sys/src/cmd/python/Demo/sockets/rpython.py+35−0
@@ -0,0 +1,35 @@
1+#! /usr/bin/env python
2+
3+# Remote python client.
4+# Execute Python commands remotely and send output back.
5+
6+import sys
7+import string
8+from socket import *
9+
10+PORT = 4127
11+BUFSIZE = 1024
12+
13+def main():
14+ if len(sys.argv) < 3:
15+ print "usage: rpython host command"
16+ sys.exit(2)
17+ host = sys.argv[1]
18+ port = PORT
19+ i = string.find(host, ':')
20+ if i >= 0:
21+ port = string.atoi(port[i+1:])
22+ host = host[:i]
23+ command = string.join(sys.argv[2:])
24+ s = socket(AF_INET, SOCK_STREAM)
25+ s.connect((host, port))
26+ s.send(command)
27+ s.shutdown(1)
28+ reply = ''
29+ while 1:
30+ data = s.recv(BUFSIZE)
31+ if not data: break
32+ reply = reply + data
33+ print reply,
34+
35+main()
sys/src/cmd/python/Demo/sockets/rpythond.py+52−0
@@ -0,0 +1,52 @@
1+#! /usr/bin/env python
2+
3+# Remote python server.
4+# Execute Python commands remotely and send output back.
5+# WARNING: This version has a gaping security hole -- it accepts requests
6+# from any host on the Internet!
7+
8+import sys
9+from socket import *
10+import StringIO
11+import traceback
12+
13+PORT = 4127
14+BUFSIZE = 1024
15+
16+def main():
17+ if len(sys.argv) > 1:
18+ port = int(eval(sys.argv[1]))
19+ else:
20+ port = PORT
21+ s = socket(AF_INET, SOCK_STREAM)
22+ s.bind(('', port))
23+ s.listen(1)
24+ while 1:
25+ conn, (remotehost, remoteport) = s.accept()
26+ print 'connected by', remotehost, remoteport
27+ request = ''
28+ while 1:
29+ data = conn.recv(BUFSIZE)
30+ if not data:
31+ break
32+ request = request + data
33+ reply = execute(request)
34+ conn.send(reply)
35+ conn.close()
36+
37+def execute(request):
38+ stdout = sys.stdout
39+ stderr = sys.stderr
40+ sys.stdout = sys.stderr = fakefile = StringIO.StringIO()
41+ try:
42+ try:
43+ exec request in {}, {}
44+ except:
45+ print
46+ traceback.print_exc(100)
47+ finally:
48+ sys.stderr = stderr
49+ sys.stdout = stdout
50+ return fakefile.getvalue()
51+
52+main()
sys/src/cmd/python/Demo/sockets/telnet.py+109−0
@@ -0,0 +1,109 @@
1+#! /usr/bin/env python
2+
3+# Minimal interface to the Internet telnet protocol.
4+#
5+# It refuses all telnet options and does not recognize any of the other
6+# telnet commands, but can still be used to connect in line-by-line mode.
7+# It's also useful to play with a number of other services,
8+# like time, finger, smtp and even ftp.
9+#
10+# Usage: telnet host [port]
11+#
12+# The port may be a service name or a decimal port number;
13+# it defaults to 'telnet'.
14+
15+
16+import sys, posix, time
17+from socket import *
18+
19+BUFSIZE = 1024
20+
21+# Telnet protocol characters
22+
23+IAC = chr(255) # Interpret as command
24+DONT = chr(254)
25+DO = chr(253)
26+WONT = chr(252)
27+WILL = chr(251)
28+
29+def main():
30+ host = sys.argv[1]
31+ try:
32+ hostaddr = gethostbyname(host)
33+ except error:
34+ sys.stderr.write(sys.argv[1] + ': bad host name\n')
35+ sys.exit(2)
36+ #
37+ if len(sys.argv) > 2:
38+ servname = sys.argv[2]
39+ else:
40+ servname = 'telnet'
41+ #
42+ if '0' <= servname[:1] <= '9':
43+ port = eval(servname)
44+ else:
45+ try:
46+ port = getservbyname(servname, 'tcp')
47+ except error:
48+ sys.stderr.write(servname + ': bad tcp service name\n')
49+ sys.exit(2)
50+ #
51+ s = socket(AF_INET, SOCK_STREAM)
52+ #
53+ try:
54+ s.connect((host, port))
55+ except error, msg:
56+ sys.stderr.write('connect failed: ' + repr(msg) + '\n')
57+ sys.exit(1)
58+ #
59+ pid = posix.fork()
60+ #
61+ if pid == 0:
62+ # child -- read stdin, write socket
63+ while 1:
64+ line = sys.stdin.readline()
65+ s.send(line)
66+ else:
67+ # parent -- read socket, write stdout
68+ iac = 0 # Interpret next char as command
69+ opt = '' # Interpret next char as option
70+ while 1:
71+ data = s.recv(BUFSIZE)
72+ if not data:
73+ # EOF; kill child and exit
74+ sys.stderr.write( '(Closed by remote host)\n')
75+ posix.kill(pid, 9)
76+ sys.exit(1)
77+ cleandata = ''
78+ for c in data:
79+ if opt:
80+ print ord(c)
81+ s.send(opt + c)
82+ opt = ''
83+ elif iac:
84+ iac = 0
85+ if c == IAC:
86+ cleandata = cleandata + c
87+ elif c in (DO, DONT):
88+ if c == DO: print '(DO)',
89+ else: print '(DONT)',
90+ opt = IAC + WONT
91+ elif c in (WILL, WONT):
92+ if c == WILL: print '(WILL)',
93+ else: print '(WONT)',
94+ opt = IAC + DONT
95+ else:
96+ print '(command)', ord(c)
97+ elif c == IAC:
98+ iac = 1
99+ print '(IAC)',
100+ else:
101+ cleandata = cleandata + c
102+ sys.stdout.write(cleandata)
103+ sys.stdout.flush()
104+
105+
106+try:
107+ main()
108+except KeyboardInterrupt:
109+ pass
sys/src/cmd/python/Demo/sockets/throughput.py+93−0
@@ -0,0 +1,93 @@
1+#! /usr/bin/env python
2+
3+# Test network throughput.
4+#
5+# Usage:
6+# 1) on host_A: throughput -s [port] # start a server
7+# 2) on host_B: throughput -c count host_A [port] # start a client
8+#
9+# The server will service multiple clients until it is killed.
10+#
11+# The client performs one transfer of count*BUFSIZE bytes and
12+# measures the time it takes (roundtrip!).
13+
14+
15+import sys, time
16+from socket import *
17+
18+MY_PORT = 50000 + 42
19+
20+BUFSIZE = 1024
21+
22+
23+def main():
24+ if len(sys.argv) < 2:
25+ usage()
26+ if sys.argv[1] == '-s':
27+ server()
28+ elif sys.argv[1] == '-c':
29+ client()
30+ else:
31+ usage()
32+
33+
34+def usage():
35+ sys.stdout = sys.stderr
36+ print 'Usage: (on host_A) throughput -s [port]'
37+ print 'and then: (on host_B) throughput -c count host_A [port]'
38+ sys.exit(2)
39+
40+
41+def server():
42+ if len(sys.argv) > 2:
43+ port = eval(sys.argv[2])
44+ else:
45+ port = MY_PORT
46+ s = socket(AF_INET, SOCK_STREAM)
47+ s.bind(('', port))
48+ s.listen(1)
49+ print 'Server ready...'
50+ while 1:
51+ conn, (host, remoteport) = s.accept()
52+ while 1:
53+ data = conn.recv(BUFSIZE)
54+ if not data:
55+ break
56+ del data
57+ conn.send('OK\n')
58+ conn.close()
59+ print 'Done with', host, 'port', remoteport
60+
61+
62+def client():
63+ if len(sys.argv) < 4:
64+ usage()
65+ count = int(eval(sys.argv[2]))
66+ host = sys.argv[3]
67+ if len(sys.argv) > 4:
68+ port = eval(sys.argv[4])
69+ else:
70+ port = MY_PORT
71+ testdata = 'x' * (BUFSIZE-1) + '\n'
72+ t1 = time.time()
73+ s = socket(AF_INET, SOCK_STREAM)
74+ t2 = time.time()
75+ s.connect((host, port))
76+ t3 = time.time()
77+ i = 0
78+ while i < count:
79+ i = i+1
80+ s.send(testdata)
81+ s.shutdown(1) # Send EOF
82+ t4 = time.time()
83+ data = s.recv(BUFSIZE)
84+ t5 = time.time()
85+ print data
86+ print 'Raw timers:', t1, t2, t3, t4, t5
87+ print 'Intervals:', t2-t1, t3-t2, t4-t3, t5-t4
88+ print 'Total:', t5-t1
89+ print 'Throughput:', round((BUFSIZE*count*0.001) / (t5-t1), 3),
90+ print 'K/sec.'
91+
92+
93+main()
sys/src/cmd/python/Demo/sockets/udpecho.py+63−0
@@ -0,0 +1,63 @@
1+#! /usr/bin/env python
2+
3+# Client and server for udp (datagram) echo.
4+#
5+# Usage: udpecho -s [port] (to start a server)
6+# or: udpecho -c host [port] <file (client)
7+
8+import sys
9+from socket import *
10+
11+ECHO_PORT = 50000 + 7
12+BUFSIZE = 1024
13+
14+def main():
15+ if len(sys.argv) < 2:
16+ usage()
17+ if sys.argv[1] == '-s':
18+ server()
19+ elif sys.argv[1] == '-c':
20+ client()
21+ else:
22+ usage()
23+
24+def usage():
25+ sys.stdout = sys.stderr
26+ print 'Usage: udpecho -s [port] (server)'
27+ print 'or: udpecho -c host [port] <file (client)'
28+ sys.exit(2)
29+
30+def server():
31+ if len(sys.argv) > 2:
32+ port = eval(sys.argv[2])
33+ else:
34+ port = ECHO_PORT
35+ s = socket(AF_INET, SOCK_DGRAM)
36+ s.bind(('', port))
37+ print 'udp echo server ready'
38+ while 1:
39+ data, addr = s.recvfrom(BUFSIZE)
40+ print 'server received %r from %r' % (data, addr)
41+ s.sendto(data, addr)
42+
43+def client():
44+ if len(sys.argv) < 3:
45+ usage()
46+ host = sys.argv[2]
47+ if len(sys.argv) > 3:
48+ port = eval(sys.argv[3])
49+ else:
50+ port = ECHO_PORT
51+ addr = host, port
52+ s = socket(AF_INET, SOCK_DGRAM)
53+ s.bind(('', 0))
54+ print 'udp echo client ready, reading stdin'
55+ while 1:
56+ line = sys.stdin.readline()
57+ if not line:
58+ break
59+ s.sendto(line, addr)
60+ data, fromaddr = s.recvfrom(BUFSIZE)
61+ print 'client received %r from %r' % (data, fromaddr)
62+
63+main()
sys/src/cmd/python/Demo/sockets/unicast.py+14−0
@@ -0,0 +1,14 @@
1+# Send UDP broadcast packets
2+
3+MYPORT = 50000
4+
5+import sys, time
6+from socket import *
7+
8+s = socket(AF_INET, SOCK_DGRAM)
9+s.bind(('', 0))
10+
11+while 1:
12+ data = repr(time.time()) + '\n'
13+ s.sendto(data, ('', MYPORT))
14+ time.sleep(2)
sys/src/cmd/python/Demo/sockets/unixclient.py+12−0
@@ -0,0 +1,12 @@
1+# Echo client demo using Unix sockets
2+# Piet van Oostrum
3+
4+from socket import *
5+
6+FILE = 'unix-socket'
7+s = socket(AF_UNIX, SOCK_STREAM)
8+s.connect(FILE)
9+s.send('Hello, world')
10+data = s.recv(1024)
11+s.close()
12+print 'Received', repr(data)
sys/src/cmd/python/Demo/sockets/unixserver.py+24−0
@@ -0,0 +1,24 @@
1+# Echo server demo using Unix sockets (handles one connection only)
2+# Piet van Oostrum
3+
4+import os
5+from socket import *
6+
7+FILE = 'unix-socket'
8+s = socket(AF_UNIX, SOCK_STREAM)
9+s.bind(FILE)
10+
11+print 'Sock name is: ['+s.getsockname()+']'
12+
13+# Wait for a connection
14+s.listen(1)
15+conn, addr = s.accept()
16+
17+while True:
18+ data = conn.recv(1024)
19+ if not data:
20+ break
21+ conn.send(data)
22+
23+conn.close()
24+os.unlink(FILE)
sys/src/cmd/python/Demo/threads/Coroutine.py+159−0
@@ -0,0 +1,159 @@
1+# Coroutine implementation using Python threads.
2+#
3+# Combines ideas from Guido's Generator module, and from the coroutine
4+# features of Icon and Simula 67.
5+#
6+# To run a collection of functions as coroutines, you need to create
7+# a Coroutine object to control them:
8+# co = Coroutine()
9+# and then 'create' a subsidiary object for each function in the
10+# collection:
11+# cof1 = co.create(f1 [, arg1, arg2, ...]) # [] means optional,
12+# cof2 = co.create(f2 [, arg1, arg2, ...]) #... not list
13+# cof3 = co.create(f3 [, arg1, arg2, ...])
14+# etc. The functions need not be distinct; 'create'ing the same
15+# function multiple times gives you independent instances of the
16+# function.
17+#
18+# To start the coroutines running, use co.tran on one of the create'd
19+# functions; e.g., co.tran(cof2). The routine that first executes
20+# co.tran is called the "main coroutine". It's special in several
21+# respects: it existed before you created the Coroutine object; if any of
22+# the create'd coroutines exits (does a return, or suffers an unhandled
23+# exception), EarlyExit error is raised in the main coroutine; and the
24+# co.detach() method transfers control directly to the main coroutine
25+# (you can't use co.tran() for this because the main coroutine doesn't
26+# have a name ...).
27+#
28+# Coroutine objects support these methods:
29+#
30+# handle = .create(func [, arg1, arg2, ...])
31+# Creates a coroutine for an invocation of func(arg1, arg2, ...),
32+# and returns a handle ("name") for the coroutine so created. The
33+# handle can be used as the target in a subsequent .tran().
34+#
35+# .tran(target, data=None)
36+# Transfer control to the create'd coroutine "target", optionally
37+# passing it an arbitrary piece of data. To the coroutine A that does
38+# the .tran, .tran acts like an ordinary function call: another
39+# coroutine B can .tran back to it later, and if it does A's .tran
40+# returns the 'data' argument passed to B's tran. E.g.,
41+#
42+# in coroutine coA in coroutine coC in coroutine coB
43+# x = co.tran(coC) co.tran(coB) co.tran(coA,12)
44+# print x # 12
45+#
46+# The data-passing feature is taken from Icon, and greatly cuts
47+# the need to use global variables for inter-coroutine communication.
48+#
49+# .back( data=None )
50+# The same as .tran(invoker, data=None), where 'invoker' is the
51+# coroutine that most recently .tran'ed control to the coroutine
52+# doing the .back. This is akin to Icon's "&source".
53+#
54+# .detach( data=None )
55+# The same as .tran(main, data=None), where 'main' is the
56+# (unnameable!) coroutine that started it all. 'main' has all the
57+# rights of any other coroutine: upon receiving control, it can
58+# .tran to an arbitrary coroutine of its choosing, go .back to
59+# the .detach'er, or .kill the whole thing.
60+#
61+# .kill()
62+# Destroy all the coroutines, and return control to the main
63+# coroutine. None of the create'ed coroutines can be resumed after a
64+# .kill(). An EarlyExit exception does a .kill() automatically. It's
65+# a good idea to .kill() coroutines you're done with, since the
66+# current implementation consumes a thread for each coroutine that
67+# may be resumed.
68+
69+import thread
70+import sync
71+
72+class _CoEvent:
73+ def __init__(self, func):
74+ self.f = func
75+ self.e = sync.event()
76+
77+ def __repr__(self):
78+ if self.f is None:
79+ return 'main coroutine'
80+ else:
81+ return 'coroutine for func ' + self.f.func_name
82+
83+ def __hash__(self):
84+ return id(self)
85+
86+ def __cmp__(x,y):
87+ return cmp(id(x), id(y))
88+
89+ def resume(self):
90+ self.e.post()
91+
92+ def wait(self):
93+ self.e.wait()
94+ self.e.clear()
95+
96+Killed = 'Coroutine.Killed'
97+EarlyExit = 'Coroutine.EarlyExit'
98+
99+class Coroutine:
100+ def __init__(self):
101+ self.active = self.main = _CoEvent(None)
102+ self.invokedby = {self.main: None}
103+ self.killed = 0
104+ self.value = None
105+ self.terminated_by = None
106+
107+ def create(self, func, *args):
108+ me = _CoEvent(func)
109+ self.invokedby[me] = None
110+ thread.start_new_thread(self._start, (me,) + args)
111+ return me
112+
113+ def _start(self, me, *args):
114+ me.wait()
115+ if not self.killed:
116+ try:
117+ try:
118+ apply(me.f, args)
119+ except Killed:
120+ pass
121+ finally:
122+ if not self.killed:
123+ self.terminated_by = me
124+ self.kill()
125+
126+ def kill(self):
127+ if self.killed:
128+ raise TypeError, 'kill() called on dead coroutines'
129+ self.killed = 1
130+ for coroutine in self.invokedby.keys():
131+ coroutine.resume()
132+
133+ def back(self, data=None):
134+ return self.tran( self.invokedby[self.active], data )
135+
136+ def detach(self, data=None):
137+ return self.tran( self.main, data )
138+
139+ def tran(self, target, data=None):
140+ if not self.invokedby.has_key(target):
141+ raise TypeError, '.tran target %r is not an active coroutine' % (target,)
142+ if self.killed:
143+ raise TypeError, '.tran target %r is killed' % (target,)
144+ self.value = data
145+ me = self.active
146+ self.invokedby[target] = me
147+ self.active = target
148+ target.resume()
149+
150+ me.wait()
151+ if self.killed:
152+ if self.main is not me:
153+ raise Killed
154+ if self.terminated_by is not None:
155+ raise EarlyExit, '%r terminated early' % (self.terminated_by,)
156+
157+ return self.value
158+
159+# end of module
sys/src/cmd/python/Demo/threads/Generator.py+84−0
@@ -0,0 +1,84 @@
1+# Generator implementation using threads
2+
3+import thread
4+
5+Killed = 'Generator.Killed'
6+
7+class Generator:
8+ # Constructor
9+ def __init__(self, func, args):
10+ self.getlock = thread.allocate_lock()
11+ self.putlock = thread.allocate_lock()
12+ self.getlock.acquire()
13+ self.putlock.acquire()
14+ self.func = func
15+ self.args = args
16+ self.done = 0
17+ self.killed = 0
18+ thread.start_new_thread(self._start, ())
19+ # Internal routine
20+ def _start(self):
21+ try:
22+ self.putlock.acquire()
23+ if not self.killed:
24+ try:
25+ apply(self.func, (self,) + self.args)
26+ except Killed:
27+ pass
28+ finally:
29+ if not self.killed:
30+ self.done = 1
31+ self.getlock.release()
32+ # Called by producer for each value; raise Killed if no more needed
33+ def put(self, value):
34+ if self.killed:
35+ raise TypeError, 'put() called on killed generator'
36+ self.value = value
37+ self.getlock.release() # Resume consumer thread
38+ self.putlock.acquire() # Wait for next get() call
39+ if self.killed:
40+ raise Killed
41+ # Called by producer to get next value; raise EOFError if no more
42+ def get(self):
43+ if self.killed:
44+ raise TypeError, 'get() called on killed generator'
45+ self.putlock.release() # Resume producer thread
46+ self.getlock.acquire() # Wait for value to appear
47+ if self.done:
48+ raise EOFError # Say there are no more values
49+ return self.value
50+ # Called by consumer if no more values wanted
51+ def kill(self):
52+ if self.killed:
53+ raise TypeError, 'kill() called on killed generator'
54+ self.killed = 1
55+ self.putlock.release()
56+ # Clone constructor
57+ def clone(self):
58+ return Generator(self.func, self.args)
59+
60+def pi(g):
61+ k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L
62+ while 1:
63+ # Next approximation
64+ p, q, k = k*k, 2L*k+1L, k+1L
65+ a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
66+ # Print common digits
67+ d, d1 = a/b, a1/b1
68+ while d == d1:
69+ g.put(int(d))
70+ a, a1 = 10L*(a%b), 10L*(a1%b1)
71+ d, d1 = a/b, a1/b1
72+
73+def test():
74+ g = Generator(pi, ())
75+ g.kill()
76+ g = Generator(pi, ())
77+ for i in range(10): print g.get(),
78+ print
79+ h = g.clone()
80+ g.kill()
81+ while 1:
82+ print h.get(),
83+
84+test()
sys/src/cmd/python/Demo/threads/README+13−0
@@ -0,0 +1,13 @@
1+This directory contains some demonstrations of the thread module.
2+
3+These are mostly "proof of concept" type applications:
4+
5+Generator.py Generator class implemented with threads.
6+find.py Parallelized "find(1)" (looks for directories).
7+sync.py Condition variables primitives by Tim Peters.
8+telnet.py Version of ../sockets/telnet.py using threads.
9+wpi.py Version of ../scripts/pi.py using threads (needs stdwin).
10+
11+Coroutine.py Coroutines using threads, by Tim Peters (22 May 94)
12+fcmp.py Example of above, by Tim
13+squasher.py Another example of above, also by Tim
sys/src/cmd/python/Demo/threads/fcmp.py+64−0
@@ -0,0 +1,64 @@
1+# Coroutine example: controlling multiple instances of a single function
2+
3+from Coroutine import *
4+
5+# fringe visits a nested list in inorder, and detaches for each non-list
6+# element; raises EarlyExit after the list is exhausted
7+def fringe(co, list):
8+ for x in list:
9+ if type(x) is type([]):
10+ fringe(co, x)
11+ else:
12+ co.back(x)
13+
14+def printinorder(list):
15+ co = Coroutine()
16+ f = co.create(fringe, co, list)
17+ try:
18+ while 1:
19+ print co.tran(f),
20+ except EarlyExit:
21+ pass
22+ print
23+
24+printinorder([1,2,3]) # 1 2 3
25+printinorder([[[[1,[2]]],3]]) # ditto
26+x = [0, 1, [2, [3]], [4,5], [[[6]]] ]
27+printinorder(x) # 0 1 2 3 4 5 6
28+
29+# fcmp lexicographically compares the fringes of two nested lists
30+def fcmp(l1, l2):
31+ co1 = Coroutine(); f1 = co1.create(fringe, co1, l1)
32+ co2 = Coroutine(); f2 = co2.create(fringe, co2, l2)
33+ while 1:
34+ try:
35+ v1 = co1.tran(f1)
36+ except EarlyExit:
37+ try:
38+ v2 = co2.tran(f2)
39+ except EarlyExit:
40+ return 0
41+ co2.kill()
42+ return -1
43+ try:
44+ v2 = co2.tran(f2)
45+ except EarlyExit:
46+ co1.kill()
47+ return 1
48+ if v1 != v2:
49+ co1.kill(); co2.kill()
50+ return cmp(v1,v2)
51+
52+print fcmp(range(7), x) # 0; fringes are equal
53+print fcmp(range(6), x) # -1; 1st list ends early
54+print fcmp(x, range(6)) # 1; 2nd list ends early
55+print fcmp(range(8), x) # 1; 2nd list ends early
56+print fcmp(x, range(8)) # -1; 1st list ends early
57+print fcmp([1,[[2],8]],
58+ [[[1],2],8]) # 0
59+print fcmp([1,[[3],8]],
60+ [[[1],2],8]) # 1
61+print fcmp([1,[[2],8]],
62+ [[[1],2],9]) # -1
63+
64+# end of example
sys/src/cmd/python/Demo/threads/find.py+155−0
@@ -0,0 +1,155 @@
1+# A parallelized "find(1)" using the thread module.
2+
3+# This demonstrates the use of a work queue and worker threads.
4+# It really does do more stats/sec when using multiple threads,
5+# although the improvement is only about 20-30 percent.
6+# (That was 8 years ago. In 2002, on Linux, I can't measure
7+# a speedup. :-( )
8+
9+# I'm too lazy to write a command line parser for the full find(1)
10+# command line syntax, so the predicate it searches for is wired-in,
11+# see function selector() below. (It currently searches for files with
12+# world write permission.)
13+
14+# Usage: parfind.py [-w nworkers] [directory] ...
15+# Default nworkers is 4
16+
17+
18+import sys
19+import getopt
20+import string
21+import time
22+import os
23+from stat import *
24+import thread
25+
26+
27+# Work queue class. Usage:
28+# wq = WorkQ()
29+# wq.addwork(func, (arg1, arg2, ...)) # one or more calls
30+# wq.run(nworkers)
31+# The work is done when wq.run() completes.
32+# The function calls executed by the workers may add more work.
33+# Don't use keyboard interrupts!
34+
35+class WorkQ:
36+
37+ # Invariants:
38+
39+ # - busy and work are only modified when mutex is locked
40+ # - len(work) is the number of jobs ready to be taken
41+ # - busy is the number of jobs being done
42+ # - todo is locked iff there is no work and somebody is busy
43+
44+ def __init__(self):
45+ self.mutex = thread.allocate()
46+ self.todo = thread.allocate()
47+ self.todo.acquire()
48+ self.work = []
49+ self.busy = 0
50+
51+ def addwork(self, func, args):
52+ job = (func, args)
53+ self.mutex.acquire()
54+ self.work.append(job)
55+ self.mutex.release()
56+ if len(self.work) == 1:
57+ self.todo.release()
58+
59+ def _getwork(self):
60+ self.todo.acquire()
61+ self.mutex.acquire()
62+ if self.busy == 0 and len(self.work) == 0:
63+ self.mutex.release()
64+ self.todo.release()
65+ return None
66+ job = self.work[0]
67+ del self.work[0]
68+ self.busy = self.busy + 1
69+ self.mutex.release()
70+ if len(self.work) > 0:
71+ self.todo.release()
72+ return job
73+
74+ def _donework(self):
75+ self.mutex.acquire()
76+ self.busy = self.busy - 1
77+ if self.busy == 0 and len(self.work) == 0:
78+ self.todo.release()
79+ self.mutex.release()
80+
81+ def _worker(self):
82+ time.sleep(0.00001) # Let other threads run
83+ while 1:
84+ job = self._getwork()
85+ if not job:
86+ break
87+ func, args = job
88+ apply(func, args)
89+ self._donework()
90+
91+ def run(self, nworkers):
92+ if not self.work:
93+ return # Nothing to do
94+ for i in range(nworkers-1):
95+ thread.start_new(self._worker, ())
96+ self._worker()
97+ self.todo.acquire()
98+
99+
100+# Main program
101+
102+def main():
103+ nworkers = 4
104+ opts, args = getopt.getopt(sys.argv[1:], '-w:')
105+ for opt, arg in opts:
106+ if opt == '-w':
107+ nworkers = string.atoi(arg)
108+ if not args:
109+ args = [os.curdir]
110+
111+ wq = WorkQ()
112+ for dir in args:
113+ wq.addwork(find, (dir, selector, wq))
114+
115+ t1 = time.time()
116+ wq.run(nworkers)
117+ t2 = time.time()
118+
119+ sys.stderr.write('Total time %r sec.\n' % (t2-t1))
120+
121+
122+# The predicate -- defines what files we look for.
123+# Feel free to change this to suit your purpose
124+
125+def selector(dir, name, fullname, stat):
126+ # Look for world writable files that are not symlinks
127+ return (stat[ST_MODE] & 0002) != 0 and not S_ISLNK(stat[ST_MODE])
128+
129+
130+# The find procedure -- calls wq.addwork() for subdirectories
131+
132+def find(dir, pred, wq):
133+ try:
134+ names = os.listdir(dir)
135+ except os.error, msg:
136+ print repr(dir), ':', msg
137+ return
138+ for name in names:
139+ if name not in (os.curdir, os.pardir):
140+ fullname = os.path.join(dir, name)
141+ try:
142+ stat = os.lstat(fullname)
143+ except os.error, msg:
144+ print repr(fullname), ':', msg
145+ continue
146+ if pred(dir, name, fullname, stat):
147+ print fullname
148+ if S_ISDIR(stat[ST_MODE]):
149+ if not os.path.ismount(fullname):
150+ wq.addwork(find, (fullname, pred, wq))
151+
152+
153+# Call the main program
154+
155+main()
sys/src/cmd/python/Demo/threads/squasher.py+105−0
@@ -0,0 +1,105 @@
1+# Coroutine example: general coroutine transfers
2+#
3+# The program is a variation of a Simula 67 program due to Dahl & Hoare,
4+# (Dahl/Dijkstra/Hoare, Structured Programming; Academic Press, 1972)
5+# who in turn credit the original example to Conway.
6+#
7+# We have a number of input lines, terminated by a 0 byte. The problem
8+# is to squash them together into output lines containing 72 characters
9+# each. A semicolon must be added between input lines. Runs of blanks
10+# and tabs in input lines must be squashed into single blanks.
11+# Occurrences of "**" in input lines must be replaced by "^".
12+#
13+# Here's a test case:
14+
15+test = """\
16+ d = sqrt(b**2 - 4*a*c)
17+twoa = 2*a
18+ L = -b/twoa
19+ R = d/twoa
20+ A1 = L + R
21+ A2 = L - R\0
22+"""
23+
24+# The program should print:
25+
26+# d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R;
27+#A2 = L - R
28+#done
29+
30+# getline: delivers the next input line to its invoker
31+# disassembler: grabs input lines from getline, and delivers them one
32+# character at a time to squasher, also inserting a semicolon into
33+# the stream between lines
34+# squasher: grabs characters from disassembler and passes them on to
35+# assembler, first replacing "**" with "^" and squashing runs of
36+# whitespace
37+# assembler: grabs characters from squasher and packs them into lines
38+# with 72 character each, delivering each such line to putline;
39+# when it sees a null byte, passes the last line to putline and
40+# then kills all the coroutines
41+# putline: grabs lines from assembler, and just prints them
42+
43+from Coroutine import *
44+
45+def getline(text):
46+ for line in string.splitfields(text, '\n'):
47+ co.tran(codisassembler, line)
48+
49+def disassembler():
50+ while 1:
51+ card = co.tran(cogetline)
52+ for i in range(len(card)):
53+ co.tran(cosquasher, card[i])
54+ co.tran(cosquasher, ';')
55+
56+def squasher():
57+ while 1:
58+ ch = co.tran(codisassembler)
59+ if ch == '*':
60+ ch2 = co.tran(codisassembler)
61+ if ch2 == '*':
62+ ch = '^'
63+ else:
64+ co.tran(coassembler, ch)
65+ ch = ch2
66+ if ch in ' \t':
67+ while 1:
68+ ch2 = co.tran(codisassembler)
69+ if ch2 not in ' \t':
70+ break
71+ co.tran(coassembler, ' ')
72+ ch = ch2
73+ co.tran(coassembler, ch)
74+
75+def assembler():
76+ line = ''
77+ while 1:
78+ ch = co.tran(cosquasher)
79+ if ch == '\0':
80+ break
81+ if len(line) == 72:
82+ co.tran(coputline, line)
83+ line = ''
84+ line = line + ch
85+ line = line + ' ' * (72 - len(line))
86+ co.tran(coputline, line)
87+ co.kill()
88+
89+def putline():
90+ while 1:
91+ line = co.tran(coassembler)
92+ print line
93+
94+import string
95+co = Coroutine()
96+cogetline = co.create(getline, test)
97+coputline = co.create(putline)
98+coassembler = co.create(assembler)
99+codisassembler = co.create(disassembler)
100+cosquasher = co.create(squasher)
101+
102+co.tran(coputline)
103+print 'done'
104+
105+# end of example
sys/src/cmd/python/Demo/threads/sync.py+603−0
@@ -0,0 +1,603 @@
1+# Defines classes that provide synchronization objects. Note that use of
2+# this module requires that your Python support threads.
3+#
4+# condition(lock=None) # a POSIX-like condition-variable object
5+# barrier(n) # an n-thread barrier
6+# event() # an event object
7+# semaphore(n=1) # a semaphore object, with initial count n
8+# mrsw() # a multiple-reader single-writer lock
9+#
10+# CONDITIONS
11+#
12+# A condition object is created via
13+# import this_module
14+# your_condition_object = this_module.condition(lock=None)
15+#
16+# As explained below, a condition object has a lock associated with it,
17+# used in the protocol to protect condition data. You can specify a
18+# lock to use in the constructor, else the constructor will allocate
19+# an anonymous lock for you. Specifying a lock explicitly can be useful
20+# when more than one condition keys off the same set of shared data.
21+#
22+# Methods:
23+# .acquire()
24+# acquire the lock associated with the condition
25+# .release()
26+# release the lock associated with the condition
27+# .wait()
28+# block the thread until such time as some other thread does a
29+# .signal or .broadcast on the same condition, and release the
30+# lock associated with the condition. The lock associated with
31+# the condition MUST be in the acquired state at the time
32+# .wait is invoked.
33+# .signal()
34+# wake up exactly one thread (if any) that previously did a .wait
35+# on the condition; that thread will awaken with the lock associated
36+# with the condition in the acquired state. If no threads are
37+# .wait'ing, this is a nop. If more than one thread is .wait'ing on
38+# the condition, any of them may be awakened.
39+# .broadcast()
40+# wake up all threads (if any) that are .wait'ing on the condition;
41+# the threads are woken up serially, each with the lock in the
42+# acquired state, so should .release() as soon as possible. If no
43+# threads are .wait'ing, this is a nop.
44+#
45+# Note that if a thread does a .wait *while* a signal/broadcast is
46+# in progress, it's guaranteeed to block until a subsequent
47+# signal/broadcast.
48+#
49+# Secret feature: `broadcast' actually takes an integer argument,
50+# and will wake up exactly that many waiting threads (or the total
51+# number waiting, if that's less). Use of this is dubious, though,
52+# and probably won't be supported if this form of condition is
53+# reimplemented in C.
54+#
55+# DIFFERENCES FROM POSIX
56+#
57+# + A separate mutex is not needed to guard condition data. Instead, a
58+# condition object can (must) be .acquire'ed and .release'ed directly.
59+# This eliminates a common error in using POSIX conditions.
60+#
61+# + Because of implementation difficulties, a POSIX `signal' wakes up
62+# _at least_ one .wait'ing thread. Race conditions make it difficult
63+# to stop that. This implementation guarantees to wake up only one,
64+# but you probably shouldn't rely on that.
65+#
66+# PROTOCOL
67+#
68+# Condition objects are used to block threads until "some condition" is
69+# true. E.g., a thread may wish to wait until a producer pumps out data
70+# for it to consume, or a server may wish to wait until someone requests
71+# its services, or perhaps a whole bunch of threads want to wait until a
72+# preceding pass over the data is complete. Early models for conditions
73+# relied on some other thread figuring out when a blocked thread's
74+# condition was true, and made the other thread responsible both for
75+# waking up the blocked thread and guaranteeing that it woke up with all
76+# data in a correct state. This proved to be very delicate in practice,
77+# and gave conditions a bad name in some circles.
78+#
79+# The POSIX model addresses these problems by making a thread responsible
80+# for ensuring that its own state is correct when it wakes, and relies
81+# on a rigid protocol to make this easy; so long as you stick to the
82+# protocol, POSIX conditions are easy to "get right":
83+#
84+# A) The thread that's waiting for some arbitrarily-complex condition
85+# (ACC) to become true does:
86+#
87+# condition.acquire()
88+# while not (code to evaluate the ACC):
89+# condition.wait()
90+# # That blocks the thread, *and* releases the lock. When a
91+# # condition.signal() happens, it will wake up some thread that
92+# # did a .wait, *and* acquire the lock again before .wait
93+# # returns.
94+# #
95+# # Because the lock is acquired at this point, the state used
96+# # in evaluating the ACC is frozen, so it's safe to go back &
97+# # reevaluate the ACC.
98+#
99+# # At this point, ACC is true, and the thread has the condition
100+# # locked.
101+# # So code here can safely muck with the shared state that
102+# # went into evaluating the ACC -- if it wants to.
103+# # When done mucking with the shared state, do
104+# condition.release()
105+#
106+# B) Threads that are mucking with shared state that may affect the
107+# ACC do:
108+#
109+# condition.acquire()
110+# # muck with shared state
111+# condition.release()
112+# if it's possible that ACC is true now:
113+# condition.signal() # or .broadcast()
114+#
115+# Note: You may prefer to put the "if" clause before the release().
116+# That's fine, but do note that anyone waiting on the signal will
117+# stay blocked until the release() is done (since acquiring the
118+# condition is part of what .wait() does before it returns).
119+#
120+# TRICK OF THE TRADE
121+#
122+# With simpler forms of conditions, it can be impossible to know when
123+# a thread that's supposed to do a .wait has actually done it. But
124+# because this form of condition releases a lock as _part_ of doing a
125+# wait, the state of that lock can be used to guarantee it.
126+#
127+# E.g., suppose thread A spawns thread B and later wants to wait for B to
128+# complete:
129+#
130+# In A: In B:
131+#
132+# B_done = condition() ... do work ...
133+# B_done.acquire() B_done.acquire(); B_done.release()
134+# spawn B B_done.signal()
135+# ... some time later ... ... and B exits ...
136+# B_done.wait()
137+#
138+# Because B_done was in the acquire'd state at the time B was spawned,
139+# B's attempt to acquire B_done can't succeed until A has done its
140+# B_done.wait() (which releases B_done). So B's B_done.signal() is
141+# guaranteed to be seen by the .wait(). Without the lock trick, B
142+# may signal before A .waits, and then A would wait forever.
143+#
144+# BARRIERS
145+#
146+# A barrier object is created via
147+# import this_module
148+# your_barrier = this_module.barrier(num_threads)
149+#
150+# Methods:
151+# .enter()
152+# the thread blocks until num_threads threads in all have done
153+# .enter(). Then the num_threads threads that .enter'ed resume,
154+# and the barrier resets to capture the next num_threads threads
155+# that .enter it.
156+#
157+# EVENTS
158+#
159+# An event object is created via
160+# import this_module
161+# your_event = this_module.event()
162+#
163+# An event has two states, `posted' and `cleared'. An event is
164+# created in the cleared state.
165+#
166+# Methods:
167+#
168+# .post()
169+# Put the event in the posted state, and resume all threads
170+# .wait'ing on the event (if any).
171+#
172+# .clear()
173+# Put the event in the cleared state.
174+#
175+# .is_posted()
176+# Returns 0 if the event is in the cleared state, or 1 if the event
177+# is in the posted state.
178+#
179+# .wait()
180+# If the event is in the posted state, returns immediately.
181+# If the event is in the cleared state, blocks the calling thread
182+# until the event is .post'ed by another thread.
183+#
184+# Note that an event, once posted, remains posted until explicitly
185+# cleared. Relative to conditions, this is both the strength & weakness
186+# of events. It's a strength because the .post'ing thread doesn't have to
187+# worry about whether the threads it's trying to communicate with have
188+# already done a .wait (a condition .signal is seen only by threads that
189+# do a .wait _prior_ to the .signal; a .signal does not persist). But
190+# it's a weakness because .clear'ing an event is error-prone: it's easy
191+# to mistakenly .clear an event before all the threads you intended to
192+# see the event get around to .wait'ing on it. But so long as you don't
193+# need to .clear an event, events are easy to use safely.
194+#
195+# SEMAPHORES
196+#
197+# A semaphore object is created via
198+# import this_module
199+# your_semaphore = this_module.semaphore(count=1)
200+#
201+# A semaphore has an integer count associated with it. The initial value
202+# of the count is specified by the optional argument (which defaults to
203+# 1) passed to the semaphore constructor.
204+#
205+# Methods:
206+#
207+# .p()
208+# If the semaphore's count is greater than 0, decrements the count
209+# by 1 and returns.
210+# Else if the semaphore's count is 0, blocks the calling thread
211+# until a subsequent .v() increases the count. When that happens,
212+# the count will be decremented by 1 and the calling thread resumed.
213+#
214+# .v()
215+# Increments the semaphore's count by 1, and wakes up a thread (if
216+# any) blocked by a .p(). It's an (detected) error for a .v() to
217+# increase the semaphore's count to a value larger than the initial
218+# count.
219+#
220+# MULTIPLE-READER SINGLE-WRITER LOCKS
221+#
222+# A mrsw lock is created via
223+# import this_module
224+# your_mrsw_lock = this_module.mrsw()
225+#
226+# This kind of lock is often useful with complex shared data structures.
227+# The object lets any number of "readers" proceed, so long as no thread
228+# wishes to "write". When a (one or more) thread declares its intention
229+# to "write" (e.g., to update a shared structure), all current readers
230+# are allowed to finish, and then a writer gets exclusive access; all
231+# other readers & writers are blocked until the current writer completes.
232+# Finally, if some thread is waiting to write and another is waiting to
233+# read, the writer takes precedence.
234+#
235+# Methods:
236+#
237+# .read_in()
238+# If no thread is writing or waiting to write, returns immediately.
239+# Else blocks until no thread is writing or waiting to write. So
240+# long as some thread has completed a .read_in but not a .read_out,
241+# writers are blocked.
242+#
243+# .read_out()
244+# Use sometime after a .read_in to declare that the thread is done
245+# reading. When all threads complete reading, a writer can proceed.
246+#
247+# .write_in()
248+# If no thread is writing (has completed a .write_in, but hasn't yet
249+# done a .write_out) or reading (similarly), returns immediately.
250+# Else blocks the calling thread, and threads waiting to read, until
251+# the current writer completes writing or all the current readers
252+# complete reading; if then more than one thread is waiting to
253+# write, one of them is allowed to proceed, but which one is not
254+# specified.
255+#
256+# .write_out()
257+# Use sometime after a .write_in to declare that the thread is done
258+# writing. Then if some other thread is waiting to write, it's
259+# allowed to proceed. Else all threads (if any) waiting to read are
260+# allowed to proceed.
261+#
262+# .write_to_read()
263+# Use instead of a .write_in to declare that the thread is done
264+# writing but wants to continue reading without other writers
265+# intervening. If there are other threads waiting to write, they
266+# are allowed to proceed only if the current thread calls
267+# .read_out; threads waiting to read are only allowed to proceed
268+# if there are are no threads waiting to write. (This is a
269+# weakness of the interface!)
270+
271+import thread
272+
273+class condition:
274+ def __init__(self, lock=None):
275+ # the lock actually used by .acquire() and .release()
276+ if lock is None:
277+ self.mutex = thread.allocate_lock()
278+ else:
279+ if hasattr(lock, 'acquire') and \
280+ hasattr(lock, 'release'):
281+ self.mutex = lock
282+ else:
283+ raise TypeError, 'condition constructor requires ' \
284+ 'a lock argument'
285+
286+ # lock used to block threads until a signal
287+ self.checkout = thread.allocate_lock()
288+ self.checkout.acquire()
289+
290+ # internal critical-section lock, & the data it protects
291+ self.idlock = thread.allocate_lock()
292+ self.id = 0
293+ self.waiting = 0 # num waiters subject to current release
294+ self.pending = 0 # num waiters awaiting next signal
295+ self.torelease = 0 # num waiters to release
296+ self.releasing = 0 # 1 iff release is in progress
297+
298+ def acquire(self):
299+ self.mutex.acquire()
300+
301+ def release(self):
302+ self.mutex.release()
303+
304+ def wait(self):
305+ mutex, checkout, idlock = self.mutex, self.checkout, self.idlock
306+ if not mutex.locked():
307+ raise ValueError, \
308+ "condition must be .acquire'd when .wait() invoked"
309+
310+ idlock.acquire()
311+ myid = self.id
312+ self.pending = self.pending + 1
313+ idlock.release()
314+
315+ mutex.release()
316+
317+ while 1:
318+ checkout.acquire(); idlock.acquire()
319+ if myid < self.id:
320+ break
321+ checkout.release(); idlock.release()
322+
323+ self.waiting = self.waiting - 1
324+ self.torelease = self.torelease - 1
325+ if self.torelease:
326+ checkout.release()
327+ else:
328+ self.releasing = 0
329+ if self.waiting == self.pending == 0:
330+ self.id = 0
331+ idlock.release()
332+ mutex.acquire()
333+
334+ def signal(self):
335+ self.broadcast(1)
336+
337+ def broadcast(self, num = -1):
338+ if num < -1:
339+ raise ValueError, '.broadcast called with num %r' % (num,)
340+ if num == 0:
341+ return
342+ self.idlock.acquire()
343+ if self.pending:
344+ self.waiting = self.waiting + self.pending
345+ self.pending = 0
346+ self.id = self.id + 1
347+ if num == -1:
348+ self.torelease = self.waiting
349+ else:
350+ self.torelease = min( self.waiting,
351+ self.torelease + num )
352+ if self.torelease and not self.releasing:
353+ self.releasing = 1
354+ self.checkout.release()
355+ self.idlock.release()
356+
357+class barrier:
358+ def __init__(self, n):
359+ self.n = n
360+ self.togo = n
361+ self.full = condition()
362+
363+ def enter(self):
364+ full = self.full
365+ full.acquire()
366+ self.togo = self.togo - 1
367+ if self.togo:
368+ full.wait()
369+ else:
370+ self.togo = self.n
371+ full.broadcast()
372+ full.release()
373+
374+class event:
375+ def __init__(self):
376+ self.state = 0
377+ self.posted = condition()
378+
379+ def post(self):
380+ self.posted.acquire()
381+ self.state = 1
382+ self.posted.broadcast()
383+ self.posted.release()
384+
385+ def clear(self):
386+ self.posted.acquire()
387+ self.state = 0
388+ self.posted.release()
389+
390+ def is_posted(self):
391+ self.posted.acquire()
392+ answer = self.state
393+ self.posted.release()
394+ return answer
395+
396+ def wait(self):
397+ self.posted.acquire()
398+ if not self.state:
399+ self.posted.wait()
400+ self.posted.release()
401+
402+class semaphore:
403+ def __init__(self, count=1):
404+ if count <= 0:
405+ raise ValueError, 'semaphore count %d; must be >= 1' % count
406+ self.count = count
407+ self.maxcount = count
408+ self.nonzero = condition()
409+
410+ def p(self):
411+ self.nonzero.acquire()
412+ while self.count == 0:
413+ self.nonzero.wait()
414+ self.count = self.count - 1
415+ self.nonzero.release()
416+
417+ def v(self):
418+ self.nonzero.acquire()
419+ if self.count == self.maxcount:
420+ raise ValueError, '.v() tried to raise semaphore count above ' \
421+ 'initial value %r' % self.maxcount
422+ self.count = self.count + 1
423+ self.nonzero.signal()
424+ self.nonzero.release()
425+
426+class mrsw:
427+ def __init__(self):
428+ # critical-section lock & the data it protects
429+ self.rwOK = thread.allocate_lock()
430+ self.nr = 0 # number readers actively reading (not just waiting)
431+ self.nw = 0 # number writers either waiting to write or writing
432+ self.writing = 0 # 1 iff some thread is writing
433+
434+ # conditions
435+ self.readOK = condition(self.rwOK) # OK to unblock readers
436+ self.writeOK = condition(self.rwOK) # OK to unblock writers
437+
438+ def read_in(self):
439+ self.rwOK.acquire()
440+ while self.nw:
441+ self.readOK.wait()
442+ self.nr = self.nr + 1
443+ self.rwOK.release()
444+
445+ def read_out(self):
446+ self.rwOK.acquire()
447+ if self.nr <= 0:
448+ raise ValueError, \
449+ '.read_out() invoked without an active reader'
450+ self.nr = self.nr - 1
451+ if self.nr == 0:
452+ self.writeOK.signal()
453+ self.rwOK.release()
454+
455+ def write_in(self):
456+ self.rwOK.acquire()
457+ self.nw = self.nw + 1
458+ while self.writing or self.nr:
459+ self.writeOK.wait()
460+ self.writing = 1
461+ self.rwOK.release()
462+
463+ def write_out(self):
464+ self.rwOK.acquire()
465+ if not self.writing:
466+ raise ValueError, \
467+ '.write_out() invoked without an active writer'
468+ self.writing = 0
469+ self.nw = self.nw - 1
470+ if self.nw:
471+ self.writeOK.signal()
472+ else:
473+ self.readOK.broadcast()
474+ self.rwOK.release()
475+
476+ def write_to_read(self):
477+ self.rwOK.acquire()
478+ if not self.writing:
479+ raise ValueError, \
480+ '.write_to_read() invoked without an active writer'
481+ self.writing = 0
482+ self.nw = self.nw - 1
483+ self.nr = self.nr + 1
484+ if not self.nw:
485+ self.readOK.broadcast()
486+ self.rwOK.release()
487+
488+# The rest of the file is a test case, that runs a number of parallelized
489+# quicksorts in parallel. If it works, you'll get about 600 lines of
490+# tracing output, with a line like
491+# test passed! 209 threads created in all
492+# as the last line. The content and order of preceding lines will
493+# vary across runs.
494+
495+def _new_thread(func, *args):
496+ global TID
497+ tid.acquire(); id = TID = TID+1; tid.release()
498+ io.acquire(); alive.append(id); \
499+ print 'starting thread', id, '--', len(alive), 'alive'; \
500+ io.release()
501+ thread.start_new_thread( func, (id,) + args )
502+
503+def _qsort(tid, a, l, r, finished):
504+ # sort a[l:r]; post finished when done
505+ io.acquire(); print 'thread', tid, 'qsort', l, r; io.release()
506+ if r-l > 1:
507+ pivot = a[l]
508+ j = l+1 # make a[l:j] <= pivot, and a[j:r] > pivot
509+ for i in range(j, r):
510+ if a[i] <= pivot:
511+ a[j], a[i] = a[i], a[j]
512+ j = j + 1
513+ a[l], a[j-1] = a[j-1], pivot
514+
515+ l_subarray_sorted = event()
516+ r_subarray_sorted = event()
517+ _new_thread(_qsort, a, l, j-1, l_subarray_sorted)
518+ _new_thread(_qsort, a, j, r, r_subarray_sorted)
519+ l_subarray_sorted.wait()
520+ r_subarray_sorted.wait()
521+
522+ io.acquire(); print 'thread', tid, 'qsort done'; \
523+ alive.remove(tid); io.release()
524+ finished.post()
525+
526+def _randarray(tid, a, finished):
527+ io.acquire(); print 'thread', tid, 'randomizing array'; \
528+ io.release()
529+ for i in range(1, len(a)):
530+ wh.acquire(); j = randint(0,i); wh.release()
531+ a[i], a[j] = a[j], a[i]
532+ io.acquire(); print 'thread', tid, 'randomizing done'; \
533+ alive.remove(tid); io.release()
534+ finished.post()
535+
536+def _check_sort(a):
537+ if a != range(len(a)):
538+ raise ValueError, ('a not sorted', a)
539+
540+def _run_one_sort(tid, a, bar, done):
541+ # randomize a, and quicksort it
542+ # for variety, all the threads running this enter a barrier
543+ # at the end, and post `done' after the barrier exits
544+ io.acquire(); print 'thread', tid, 'randomizing', a; \
545+ io.release()
546+ finished = event()
547+ _new_thread(_randarray, a, finished)
548+ finished.wait()
549+
550+ io.acquire(); print 'thread', tid, 'sorting', a; io.release()
551+ finished.clear()
552+ _new_thread(_qsort, a, 0, len(a), finished)
553+ finished.wait()
554+ _check_sort(a)
555+
556+ io.acquire(); print 'thread', tid, 'entering barrier'; \
557+ io.release()
558+ bar.enter()
559+ io.acquire(); print 'thread', tid, 'leaving barrier'; \
560+ io.release()
561+ io.acquire(); alive.remove(tid); io.release()
562+ bar.enter() # make sure they've all removed themselves from alive
563+ ## before 'done' is posted
564+ bar.enter() # just to be cruel
565+ done.post()
566+
567+def test():
568+ global TID, tid, io, wh, randint, alive
569+ import random
570+ randint = random.randint
571+
572+ TID = 0 # thread ID (1, 2, ...)
573+ tid = thread.allocate_lock() # for changing TID
574+ io = thread.allocate_lock() # for printing, and 'alive'
575+ wh = thread.allocate_lock() # for calls to random
576+ alive = [] # IDs of active threads
577+
578+ NSORTS = 5
579+ arrays = []
580+ for i in range(NSORTS):
581+ arrays.append( range( (i+1)*10 ) )
582+
583+ bar = barrier(NSORTS)
584+ finished = event()
585+ for i in range(NSORTS):
586+ _new_thread(_run_one_sort, arrays[i], bar, finished)
587+ finished.wait()
588+
589+ print 'all threads done, and checking results ...'
590+ if alive:
591+ raise ValueError, ('threads still alive at end', alive)
592+ for i in range(NSORTS):
593+ a = arrays[i]
594+ if len(a) != (i+1)*10:
595+ raise ValueError, ('length of array', i, 'screwed up')
596+ _check_sort(a)
597+
598+ print 'test passed!', TID, 'threads created in all'
599+
600+if __name__ == '__main__':
601+ test()
602+
603+# end of module
sys/src/cmd/python/Demo/threads/telnet.py+114−0
@@ -0,0 +1,114 @@
1+# Minimal interface to the Internet telnet protocol.
2+#
3+# *** modified to use threads ***
4+#
5+# It refuses all telnet options and does not recognize any of the other
6+# telnet commands, but can still be used to connect in line-by-line mode.
7+# It's also useful to play with a number of other services,
8+# like time, finger, smtp and even ftp.
9+#
10+# Usage: telnet host [port]
11+#
12+# The port may be a service name or a decimal port number;
13+# it defaults to 'telnet'.
14+
15+
16+import sys, os, time
17+from socket import *
18+import thread
19+
20+BUFSIZE = 8*1024
21+
22+# Telnet protocol characters
23+
24+IAC = chr(255) # Interpret as command
25+DONT = chr(254)
26+DO = chr(253)
27+WONT = chr(252)
28+WILL = chr(251)
29+
30+def main():
31+ if len(sys.argv) < 2:
32+ sys.stderr.write('usage: telnet hostname [port]\n')
33+ sys.exit(2)
34+ host = sys.argv[1]
35+ try:
36+ hostaddr = gethostbyname(host)
37+ except error:
38+ sys.stderr.write(sys.argv[1] + ': bad host name\n')
39+ sys.exit(2)
40+ #
41+ if len(sys.argv) > 2:
42+ servname = sys.argv[2]
43+ else:
44+ servname = 'telnet'
45+ #
46+ if '0' <= servname[:1] <= '9':
47+ port = eval(servname)
48+ else:
49+ try:
50+ port = getservbyname(servname, 'tcp')
51+ except error:
52+ sys.stderr.write(servname + ': bad tcp service name\n')
53+ sys.exit(2)
54+ #
55+ s = socket(AF_INET, SOCK_STREAM)
56+ #
57+ try:
58+ s.connect((host, port))
59+ except error, msg:
60+ sys.stderr.write('connect failed: %r\n' % (msg,))
61+ sys.exit(1)
62+ #
63+ thread.start_new(child, (s,))
64+ parent(s)
65+
66+def parent(s):
67+ # read socket, write stdout
68+ iac = 0 # Interpret next char as command
69+ opt = '' # Interpret next char as option
70+ while 1:
71+ data, dummy = s.recvfrom(BUFSIZE)
72+ if not data:
73+ # EOF -- exit
74+ sys.stderr.write( '(Closed by remote host)\n')
75+ sys.exit(1)
76+ cleandata = ''
77+ for c in data:
78+ if opt:
79+ print ord(c)
80+## print '(replying: %r)' % (opt+c,)
81+ s.send(opt + c)
82+ opt = ''
83+ elif iac:
84+ iac = 0
85+ if c == IAC:
86+ cleandata = cleandata + c
87+ elif c in (DO, DONT):
88+ if c == DO: print '(DO)',
89+ else: print '(DONT)',
90+ opt = IAC + WONT
91+ elif c in (WILL, WONT):
92+ if c == WILL: print '(WILL)',
93+ else: print '(WONT)',
94+ opt = IAC + DONT
95+ else:
96+ print '(command)', ord(c)
97+ elif c == IAC:
98+ iac = 1
99+ print '(IAC)',
100+ else:
101+ cleandata = cleandata + c
102+ sys.stdout.write(cleandata)
103+ sys.stdout.flush()
104+## print 'Out:', repr(cleandata)
105+
106+def child(s):
107+ # read stdin, write socket
108+ while 1:
109+ line = sys.stdin.readline()
110+## print 'Got:', repr(line)
111+ if not line: break
112+ s.send(line)
113+
114+main()
sys/src/cmd/python/Demo/tix/INSTALL.txt+89−0
@@ -0,0 +1,89 @@
1+$Id: INSTALL.txt 24230 2001-11-11 14:07:37Z loewis $
2+
3+Installing Tix.py
4+----------------
5+
6+0) To use Tix.py, you need Tcl/Tk (V8.3.3), Tix (V8.1.1) and Python (V2.1.1).
7+ Tix.py has been written and tested on a Intel Pentium running RH Linux 5.2
8+ and Mandrake Linux 7.0 and Windows with the above mentioned packages.
9+
10+ Older versions, e.g. Tix 4.1 and Tk 8.0, might also work.
11+
12+ There is nothing OS-specific in Tix.py itself so it should work on
13+ any machine with Tix and Python installed. You can get Tcl and Tk
14+ from http://dev.scriptics.com and Tix from http://tix.sourceforge.net.
15+
16+1) Build and install Tcl/Tk 8.3. Build and install Tix 8.1.
17+ Ensure that Tix is properly installed by running tixwish and executing
18+ the demo programs. Under Unix, use the --enable-shared configure option
19+ for all three. We recommend tcl8.3.3 for this release of Tix.py.
20+
21+2a) If you have a distribution like ActiveState with a tcl subdirectory
22+ of $PYTHONHOME, which contains the directories tcl8.3 and tk8.3,
23+ make a directory tix8.1 as well. Recursively copy the files from
24+ <tix>/library to $PYTHONHOME/lib/tix8.1, and copy the dynamic library
25+ (tix8183.dll or libtix8.1.8.3.so) to the same place as the tcl dynamic
26+ libraries ($PYTHONHOME/Dlls or lib/python-2.1/lib-dynload). In this
27+ case you are all installed, and you can skip to the end.
28+
29+2b) Modify Modules/Setup.dist and setup.py to change the version of the
30+ tix library from tix4.1.8.0 to tix8.1.8.3
31+ These modified files can be used for Tkinter with or without Tix.
32+
33+3) The default is to build dynamically, and use the Tcl 'package require'.
34+ To build statically, modify the Modules/Setup file to link in the Tix
35+ library according to the comments in the file. On Linux this looks like:
36+
37+# *** Always uncomment this (leave the leading underscore in!):
38+_tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \
39+# *** Uncomment and edit to reflect where your Tcl/Tk libraries are:
40+ -L/usr/local/lib \
41+# *** Uncomment and edit to reflect where your Tcl/Tk headers are:
42+ -I/usr/local/include \
43+# *** Uncomment and edit to reflect where your X11 header files are:
44+ -I/usr/X11R6/include \
45+# *** Or uncomment this for Solaris:
46+# -I/usr/openwin/include \
47+# *** Uncomment and edit for BLT extension only:
48+# -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \
49+# *** Uncomment and edit for PIL (TkImaging) extension only:
50+# (See http://www.pythonware.com/products/pil/ for more info)
51+# -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \
52+# *** Uncomment and edit for TOGL extension only:
53+# -DWITH_TOGL togl.c \
54+# *** Uncomment and edit for Tix extension only:
55+ -DWITH_TIX -ltix8.1.8.3 \
56+# *** Uncomment and edit to reflect your Tcl/Tk versions:
57+ -ltk8.3 -ltcl8.3 \
58+# *** Uncomment and edit to reflect where your X11 libraries are:
59+ -L/usr/X11R6/lib \
60+# *** Or uncomment this for Solaris:
61+# -L/usr/openwin/lib \
62+# *** Uncomment these for TOGL extension only:
63+# -lGL -lGLU -lXext -lXmu \
64+# *** Uncomment for AIX:
65+# -lld \
66+# *** Always uncomment this; X11 libraries to link with:
67+ -lX11
68+
69+4) Rebuild Python and reinstall.
70+
71+You should now have a working Tix implementation in Python. To see if all
72+is as it should be, run the 'tixwidgets.py' script in the Demo/tix directory.
73+Under X windows, do
74+ /usr/local/bin/python Demo/tix/tixwidgets.py
75+
76+If this does not work, you may need to tell python where to find
77+the Tcl, Tk and Tix library files. This is done by setting the
78+TCL_LIBRARY, TK_LIBRARY and TIX_LIBRARY environment variables. Try this:
79+
80+ env TCL_LIBRARY=/usr/local/lib/tcl8.3 \
81+ TK_LIBRARY=/usr/local/lib/tk8.3 \
82+ TIX_LIBRARY=/usr/local/lib/tix8.1 \
83+ /usr/local/bin/python Demo/tix/tixwidgets.py
84+
85+
86+If you find any bugs or have suggestions for improvement, please report them
87+via http://tix.sourceforge.net
88+
89+
sys/src/cmd/python/Demo/tix/README.txt+19−0
@@ -0,0 +1,19 @@
1+About Tix.py
2+-----------
3+
4+Tix.py is based on an idea of Jean-Marc Lugrin (lugrin@ms.com) who wrote
5+pytix (another Python-Tix marriage). Tix widgets are an attractive and
6+useful extension to Tk. See http://tix.sourceforge.net
7+for more details about Tix and how to get it.
8+
9+Features:
10+ 1) It is almost complete.
11+ 2) Tix widgets are represented by classes in Python. Sub-widgets
12+ are members of the mega-widget class. For example, if a
13+ particular TixWidget (e.g. ScrolledText) has an embedded widget
14+ (Text in this case), it is possible to call the methods of the
15+ child directly.
16+ 3) The members of the class are created automatically. In the case
17+ of widgets like ButtonBox, the members are added dynamically.
18+
19+
sys/src/cmd/python/Demo/tix/bitmaps/about.xpm+50−0
@@ -0,0 +1,50 @@
1+/* XPM */
2+static char * about_xpm[] = {
3+"50 40 7 1",
4+" s None c None",
5+". c black",
6+"X c white",
7+"o c gray70",
8+"O c navy",
9+"+ c red",
10+"@ c yellow",
11+" ",
12+" ",
13+" ",
14+" ................................. ",
15+" ..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoo. ",
16+" .XooooooooooooooooooooooooooooooXo. ",
17+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXooXo. ",
18+" ..oooooooooooooooooooooooooooooooXo. ",
19+" ...............................XoXo. ",
20+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
21+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
22+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
23+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
24+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo.++++ ",
25+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo+++ ",
26+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo+++++ ",
27+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo++++++ ",
28+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo+++ + ",
29+" .OOOOO@@@@@OOOOOOOOOOOOOOOOOOO.Xo++. ",
30+" .OOOOOOO@OOOOO@OOOOOOOOOOOOOOO.XoXo. ",
31+" .OOOOOOO@OOOOOOOOOOOOOOOOOOOOO.XoXo. ",
32+" .OOOOOOO@OOOO@@OOO@OOO@OOOOOOO.XoXo. ",
33+" .OOOOOOO@OOOOO@OOOO@O@OOOOOOOO.XoXo. ",
34+" .OOOOOOO@OOOOO@OOOOO@OOOOOOOOO.XoXo. ",
35+" .OOOOOOO@OOOOO@OOOOO@OOOOOOOOO.XoXo. ",
36+" .OOOOOOO@OOOOO@OOOO@O@OOOOOOOO.XoXo. ",
37+" .OOOOOOO@OOOO@@@OO@OOO@OOOOOOO.XoXo. ",
38+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
39+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
40+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
41+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
42+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
43+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XoXo. ",
44+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo.. ",
45+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo ",
46+" OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.X. ",
47+" ............................. ",
48+" ",
49+" ",
50+" "};
sys/src/cmd/python/Demo/tix/bitmaps/bold.xbm+6−0
@@ -0,0 +1,6 @@
1+#define bold_width 16
2+#define bold_height 16
3+static unsigned char bold_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x0f, 0x18, 0x1c, 0x18, 0x18,
5+ 0x18, 0x18, 0x18, 0x1c, 0xf8, 0x0f, 0xf8, 0x0f, 0x18, 0x18, 0x18, 0x30,
6+ 0x18, 0x30, 0x18, 0x38, 0xfc, 0x3f, 0xfc, 0x1f};
sys/src/cmd/python/Demo/tix/bitmaps/capital.xbm+6−0
@@ -0,0 +1,6 @@
1+#define capital_width 16
2+#define capital_height 16
3+static unsigned char capital_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x08, 0x30, 0x0c, 0x30, 0x06,
5+ 0x30, 0x03, 0xb0, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x01, 0xb0, 0x03,
6+ 0x30, 0x07, 0x30, 0x0e, 0x30, 0x1c, 0x00, 0x00};
sys/src/cmd/python/Demo/tix/bitmaps/centerj.xbm+6−0
@@ -0,0 +1,6 @@
1+#define centerj_width 16
2+#define centerj_height 16
3+static unsigned char centerj_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3e, 0x00, 0x00, 0xc0, 0x0d,
5+ 0x00, 0x00, 0x58, 0x77, 0x00, 0x00, 0xb0, 0x3b, 0x00, 0x00, 0xdc, 0xf7,
6+ 0x00, 0x00, 0xf0, 0x3e, 0x00, 0x00, 0xd8, 0x7e};
sys/src/cmd/python/Demo/tix/bitmaps/combobox.xbm+14−0
@@ -0,0 +1,14 @@
1+#define combobox_width 32
2+#define combobox_height 32
3+static unsigned char combobox_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5+ 0xfc, 0xff, 0xff, 0x3e, 0x04, 0x00, 0x80, 0x2a, 0x04, 0x00, 0x80, 0x2a,
6+ 0x04, 0x00, 0x80, 0x2a, 0x04, 0x00, 0x80, 0x2b, 0xfc, 0xff, 0xff, 0x3e,
7+ 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x3e, 0x08, 0x00, 0x00, 0x2a,
8+ 0x28, 0x49, 0x00, 0x2a, 0x08, 0x00, 0x00, 0x3e, 0x08, 0x00, 0x00, 0x22,
9+ 0x08, 0x00, 0x00, 0x22, 0x28, 0x49, 0x12, 0x22, 0x08, 0x00, 0x00, 0x22,
10+ 0x08, 0x00, 0x00, 0x22, 0x08, 0x00, 0x00, 0x22, 0x28, 0x49, 0x02, 0x22,
11+ 0x08, 0x00, 0x00, 0x3e, 0x08, 0x00, 0x00, 0x2a, 0x08, 0x00, 0x00, 0x2a,
12+ 0xf8, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
sys/src/cmd/python/Demo/tix/bitmaps/combobox.xpm+49−0
@@ -0,0 +1,49 @@
1+/* XPM */
2+static char * combobox_xpm[] = {
3+"50 40 6 1",
4+" s None c None",
5+". c black",
6+"X c white",
7+"o c #FFFF80808080",
8+"O c gray70",
9+"+ c #808000008080",
10+" ",
11+" ",
12+" ",
13+" .................................... XXXXXXX ",
14+" .ooooooooooooooooooooooooooooooooooX X . . ",
15+" .ooooooooooooooooooooooooooooooooooX X . . ",
16+" .oooo.oooooooooooooooooooooooooooooX X . . ",
17+" .oo.o..oo.o.oo.o.ooooooooooooooooooX X . . ",
18+" .o..o.o.o.oo.oo.oo.ooooooooooooooooX X ... . ",
19+" .oo.oo.oo.o.oo.ooo.ooooooooooooooooX X . . ",
20+" .ooooooooooooooooooooooooooooooooooX X . ",
21+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X...... ",
22+" ",
23+" ",
24+" ",
25+" XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ",
26+" X............................................ ",
27+" X.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX.OOOOX. ",
28+" X.O+OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX.OX OX. ",
29+" X.O++OOO+OO+++OOOOOOOOOOOOOOOOOOOOOOOX.X ..X. ",
30+" X.O+O+O+OOO+O+OOOOOOOOOOOOOOOOOOOOOOOX.OOOOX. ",
31+" X.O++OOO+OO+++OOOOOOOOOOOOOOOOOOOOOOOX.OOOOX. ",
32+" X.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX.XXXXX. ",
33+" X.O.....X..........................OOX.X .X. ",
34+" X.OX...XXX.X.XX.XX.................OOX.X .X. ",
35+" X.OX.X..X..X.XX..XX.X..............OOX.X .X. ",
36+" X.O.X...X..X.X...X..X..............OOX.X .X. ",
37+" X.OOOOOOOOOOOOOOOOOOOOOOOO+OOOOOOOOOOX.X .X. ",
38+" X.OOOOOOOOO+OOO+OOOOO+OOOO+OOOOOOOOOOX.X .X. ",
39+" X.O+++OO+OO+O+OO++O++OO+OO+OOOOOOOOOOX.X...X. ",
40+" X.OO+OO++OO+O+OO+OOO+OO+O++OOOOOOOOOOX.OOOOX. ",
41+" X.OOOOOOOO+OOOOO++OO+OOOOOOOOOOOOOOOOX.OOOOX. ",
42+" X.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX.X .X. ",
43+" X.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX.O .OX. ",
44+" X.OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX.OOOOX. ",
45+" X.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXX. ",
46+" X............................................ ",
47+" ",
48+" ",
49+" "};
sys/src/cmd/python/Demo/tix/bitmaps/drivea.xbm+14−0
@@ -0,0 +1,14 @@
1+#define drivea_width 32
2+#define drivea_height 32
3+static unsigned char drivea_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7+ 0xf8, 0xff, 0xff, 0x1f, 0x08, 0x00, 0x00, 0x18, 0xa8, 0xaa, 0xaa, 0x1a,
8+ 0x48, 0x55, 0xd5, 0x1d, 0xa8, 0xaa, 0xaa, 0x1b, 0x48, 0x55, 0x55, 0x1d,
9+ 0xa8, 0xfa, 0xaf, 0x1a, 0xc8, 0xff, 0xff, 0x1d, 0xa8, 0xfa, 0xaf, 0x1a,
10+ 0x48, 0x55, 0x55, 0x1d, 0xa8, 0xaa, 0xaa, 0x1a, 0x48, 0x55, 0x55, 0x1d,
11+ 0xa8, 0xaa, 0xaa, 0x1a, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f,
12+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
sys/src/cmd/python/Demo/tix/bitmaps/drivea.xpm+43−0
@@ -0,0 +1,43 @@
1+/* XPM */
2+static char * drivea_xpm[] = {
3+/* width height ncolors chars_per_pixel */
4+"32 32 5 1",
5+/* colors */
6+" s None c None",
7+". c #000000000000",
8+"X c white",
9+"o c #c000c000c000",
10+"O c #800080008000",
11+/* pixels */
12+" ",
13+" ",
14+" ",
15+" ",
16+" ",
17+" ",
18+" ",
19+" ",
20+" ",
21+" .......................... ",
22+" .XXXXXXXXXXXXXXXXXXXXXXXo. ",
23+" .XooooooooooooooooooooooO. ",
24+" .Xooooooooooooooooo..oooO. ",
25+" .Xooooooooooooooooo..oooO. ",
26+" .XooooooooooooooooooooooO. ",
27+" .Xoooooooo.......oooooooO. ",
28+" .Xoo...................oO. ",
29+" .Xoooooooo.......oooooooO. ",
30+" .XooooooooooooooooooooooO. ",
31+" .XooooooooooooooooooooooO. ",
32+" .XooooooooooooooooooooooO. ",
33+" .XooooooooooooooooooooooO. ",
34+" .oOOOOOOOOOOOOOOOOOOOOOOO. ",
35+" .......................... ",
36+" ",
37+" ",
38+" ",
39+" ",
40+" ",
41+" ",
42+" ",
43+" "};
sys/src/cmd/python/Demo/tix/bitmaps/exit.xpm+48−0
@@ -0,0 +1,48 @@
1+/* XPM */
2+static char * exit_xpm[] = {
3+"50 40 5 1",
4+" s None c None",
5+". c black",
6+"X c white",
7+"o c #000080800000",
8+"O c yellow",
9+" ",
10+" ",
11+" ",
12+" ",
13+" ",
14+" ",
15+" ",
16+" ",
17+" ",
18+" ....................................... ",
19+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. ",
20+" .XoooooooooooooooooooooooooooooooooooX. ",
21+" .XoooooooooooooooooooooooooooooooooooX. ",
22+" .XoooooooooooooooooooooooOoooooooooooX. ",
23+" .XoooooooooooooooooooooooOOooooooooooX. ",
24+" .XoooooooooooooooooooooooOOOoooooooooX. ",
25+" .XoooooOOOOOOOOOOOOOOOOOOOOOOooooooooX. ",
26+" .XoooooOOOOOOOOOOOOOOOOOOOOOOOoooooooX. ",
27+" .XoooooOOOOOOOOOOOOOOOOOOOOOOOOooooooX. ",
28+" .XoooooOOOOOOOOOOOOOOOOOOOOOOOOOoooooX. ",
29+" .XoooooOOOOOOOOOOOOOOOOOOOOOOOOooooooX. ",
30+" .XoooooOOOOOOOOOOOOOOOOOOOOOOOoooooooX. ",
31+" .XoooooOOOOOOOOOOOOOOOOOOOOOOooooooooX. ",
32+" .XoooooooooooooooooooooooOOOoooooooooX. ",
33+" .XoooooooooooooooooooooooOOooooooooooX. ",
34+" .XoooooooooooooooooooooooOoooooooooooX. ",
35+" .XoooooooooooooooooooooooooooooooooooX. ",
36+" .XoooooooooooooooooooooooooooooooooooX. ",
37+" .XoooooooooooooooooooooooooooooooooooX. ",
38+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. ",
39+" ....................................... ",
40+" ",
41+" ",
42+" ",
43+" ",
44+" ",
45+" ",
46+" ",
47+" ",
48+" "};
sys/src/cmd/python/Demo/tix/bitmaps/filebox.xbm+14−0
@@ -0,0 +1,14 @@
1+#define filebox_width 32
2+#define filebox_height 32
3+static unsigned char filebox_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0x04, 0x00, 0x00, 0x20,
6+ 0xe4, 0xff, 0xff, 0x27, 0x24, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x24,
7+ 0xe4, 0xff, 0xff, 0x27, 0x04, 0x00, 0x00, 0x20, 0xe4, 0x7f, 0xfe, 0x27,
8+ 0x24, 0x50, 0x02, 0x25, 0x24, 0x40, 0x02, 0x24, 0x24, 0x50, 0x02, 0x25,
9+ 0x24, 0x40, 0x02, 0x24, 0x24, 0x50, 0x02, 0x25, 0x24, 0x40, 0x02, 0x24,
10+ 0x24, 0x50, 0x02, 0x25, 0xe4, 0x7f, 0xfe, 0x27, 0x04, 0x00, 0x00, 0x20,
11+ 0xe4, 0xff, 0xff, 0x27, 0x24, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x24,
12+ 0xe4, 0xff, 0xff, 0x27, 0x04, 0x00, 0x00, 0x20, 0xfc, 0xff, 0xff, 0x3f,
13+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
sys/src/cmd/python/Demo/tix/bitmaps/filebox.xpm+49−0
@@ -0,0 +1,49 @@
1+/* XPM */
2+static char * filebox_xpm[] = {
3+"50 40 6 1",
4+" s None c None",
5+". c white",
6+"X c gray80",
7+"o c black",
8+"O c #FFFF80808080",
9+"+ c gray70",
10+" ",
11+" ",
12+" ",
13+" ............................................ ",
14+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
15+" .XXooXooXoXooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
16+" .XXooXooXoXooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
17+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
18+" .XXooooooooooooooooooooooooooooooooooooo.XXo ",
19+" .XXoOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XXo ",
20+" .XXoOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.XXo ",
21+" .XX......................................XXo ",
22+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
23+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
24+" .XXoooooooooooooooo.XXXXoooooooooooooooo.XXo ",
25+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
26+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
27+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
28+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
29+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
30+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
31+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
32+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
33+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
34+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
35+" .XXo+++++++++++++++.XXXXo+++++++++++++++.XXo ",
36+" .XX.................XXXX.................XXo ",
37+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
38+" .XXooXooXoXooXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
39+" .XXooXooXoXooXoXooXXXXXXXXXXXXXXXXXXXXXXXXXo ",
40+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
41+" .XXoooooooooooooooooooooooooooooooooooooo.Xo ",
42+" .XXoOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo ",
43+" .XXoOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Xo ",
44+" .XX.......................................Xo ",
45+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
46+" .ooooooooooooooooooooooooooooooooooooooooooo ",
47+" ",
48+" ",
49+" "};
sys/src/cmd/python/Demo/tix/bitmaps/italic.xbm+6−0
@@ -0,0 +1,6 @@
1+#define italic_width 16
2+#define italic_height 16
3+static unsigned char italic_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x80, 0x3f, 0x00, 0x06, 0x00, 0x06,
5+ 0x00, 0x03, 0x00, 0x03, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x00, 0xc0, 0x00,
6+ 0x60, 0x00, 0x60, 0x00, 0xfc, 0x01, 0xfc, 0x01};
sys/src/cmd/python/Demo/tix/bitmaps/justify.xbm+6−0
@@ -0,0 +1,6 @@
1+#define justify_width 16
2+#define justify_height 16
3+static unsigned char justify_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xdb, 0x00, 0x00, 0x7c, 0xdb,
5+ 0x00, 0x00, 0xbc, 0xf7, 0x00, 0x00, 0xdc, 0xde, 0x00, 0x00, 0x6c, 0xdf,
6+ 0x00, 0x00, 0x6c, 0xef, 0x00, 0x00, 0xdc, 0xdf};
sys/src/cmd/python/Demo/tix/bitmaps/leftj.xbm+6−0
@@ -0,0 +1,6 @@
1+#define leftj_width 16
2+#define leftj_height 16
3+static unsigned char leftj_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x6d, 0x00, 0x00, 0xdc, 0x01,
5+ 0x00, 0x00, 0xec, 0x0e, 0x00, 0x00, 0xfc, 0x7e, 0x00, 0x00, 0xdc, 0x03,
6+ 0x00, 0x00, 0x6c, 0x3b, 0x00, 0x00, 0x6c, 0x1f};
sys/src/cmd/python/Demo/tix/bitmaps/netw.xbm+14−0
@@ -0,0 +1,14 @@
1+#define netw_width 32
2+#define netw_height 32
3+static unsigned char netw_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x02, 0x40,
5+ 0x00, 0x00, 0xfa, 0x5f, 0x00, 0x00, 0x0a, 0x50, 0x00, 0x00, 0x0a, 0x52,
6+ 0x00, 0x00, 0x0a, 0x52, 0x00, 0x00, 0x8a, 0x51, 0x00, 0x00, 0x0a, 0x50,
7+ 0x00, 0x00, 0x4a, 0x50, 0x00, 0x00, 0x0a, 0x50, 0x00, 0x00, 0x0a, 0x50,
8+ 0x00, 0x00, 0xfa, 0x5f, 0x00, 0x00, 0x02, 0x40, 0xfe, 0x7f, 0x52, 0x55,
9+ 0x02, 0x40, 0xaa, 0x6a, 0xfa, 0x5f, 0xfe, 0x7f, 0x0a, 0x50, 0xfe, 0x7f,
10+ 0x0a, 0x52, 0x80, 0x00, 0x0a, 0x52, 0x80, 0x00, 0x8a, 0x51, 0x80, 0x00,
11+ 0x0a, 0x50, 0x80, 0x00, 0x4a, 0x50, 0x80, 0x00, 0x0a, 0x50, 0xe0, 0x03,
12+ 0x0a, 0x50, 0x20, 0x02, 0xfa, 0xdf, 0x3f, 0x03, 0x02, 0x40, 0xa0, 0x02,
13+ 0x52, 0x55, 0xe0, 0x03, 0xaa, 0x6a, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
14+ 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
sys/src/cmd/python/Demo/tix/bitmaps/netw.xpm+45−0
@@ -0,0 +1,45 @@
1+/* XPM */
2+static char * netw_xpm[] = {
3+/* width height ncolors chars_per_pixel */
4+"32 32 7 1",
5+/* colors */
6+" s None c None",
7+". c #000000000000",
8+"X c white",
9+"o c #c000c000c000",
10+"O c #404040",
11+"+ c blue",
12+"@ c red",
13+/* pixels */
14+" ",
15+" .............. ",
16+" .XXXXXXXXXXXX. ",
17+" .XooooooooooO. ",
18+" .Xo.......XoO. ",
19+" .Xo.++++o+XoO. ",
20+" .Xo.++++o+XoO. ",
21+" .Xo.++oo++XoO. ",
22+" .Xo.++++++XoO. ",
23+" .Xo.+o++++XoO. ",
24+" .Xo.++++++XoO. ",
25+" .Xo.XXXXXXXoO. ",
26+" .XooooooooooO. ",
27+" .Xo@ooo....oO. ",
28+" .............. .XooooooooooO. ",
29+" .XXXXXXXXXXXX. .XooooooooooO. ",
30+" .XooooooooooO. .OOOOOOOOOOOO. ",
31+" .Xo.......XoO. .............. ",
32+" .Xo.++++o+XoO. @ ",
33+" .Xo.++++o+XoO. @ ",
34+" .Xo.++oo++XoO. @ ",
35+" .Xo.++++++XoO. @ ",
36+" .Xo.+o++++XoO. @ ",
37+" .Xo.++++++XoO. ..... ",
38+" .Xo.XXXXXXXoO. .XXX. ",
39+" .XooooooooooO.@@@@@@.X O. ",
40+" .Xo@ooo....oO. .OOO. ",
41+" .XooooooooooO. ..... ",
42+" .XooooooooooO. ",
43+" .OOOOOOOOOOOO. ",
44+" .............. ",
45+" "};
sys/src/cmd/python/Demo/tix/bitmaps/optmenu.xpm+48−0
@@ -0,0 +1,48 @@
1+/* XPM */
2+static char * optmenu_xpm[] = {
3+"50 40 5 1",
4+" s None c None",
5+". c white",
6+"X c gray80",
7+"o c gray50",
8+"O c black",
9+" ",
10+" ",
11+" .............................. ",
12+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
13+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
14+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
15+" .XXXOXOXXOXXOXXXXOOXXXXXXXXXXo ",
16+" .XXXOXOXXOXOXXXOXXOXXXXXXXXXXo ",
17+" .XXXXOXXOXXOXXXOXXXOXXXXXXXXXo ",
18+" .XXXXOXXXOXXOOXXOXOXXXXXXXXXXo ",
19+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
20+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo.............o ",
21+" .............................o o ",
22+" ..XXXOXXXXXOXXXXXXXXOXXXXXXXOo o ",
23+" ..XXOXOXOXXOXOXXXOXXOXXXXXXXOo ...... o ",
24+" ..XXXOXXXOXXOXXXOXXXOXXXXXXXOo . o o ",
25+" ..XXOXXXOXXXOXOXXOXXOXXXXXXXOo . o o ",
26+" ..XXXXXXXXXXXXXXXXXXXXXXXXXXOo .ooooo o ",
27+" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOo o ",
28+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo o ",
29+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXooooooooooooooo ",
30+" .XXXXOXXXXXOXXXXXXXXXXXXXXXXXo ",
31+" .XXXOXXXXXXXXXOXXXXXXXXXXXXXXo ",
32+" .XXXXOXXOXXOXOXOXXXXXXXXXXXXXo ",
33+" .XXXXXOXXOXOXXXXXXXXXXXXXXXXXo ",
34+" .XXXXXXXXXXXXXOXXXXXXXXXXXXXXo ",
35+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
36+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
37+" .XXXOXOXXXXXXXOXOXXXXXOXXXXXXo ",
38+" .XXXXXOXOXOXXOXXXXXOXXOXXXXXXo ",
39+" .XXXXOXXOXOXOXXXOXOXOXXOXXXXXo ",
40+" .XXXOXXXXOXXOXXXOXXOXXXXOXXXXo ",
41+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
42+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
43+" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXo ",
44+" oooooooooooooooooooooooooooooo ",
45+" ",
46+" ",
47+" ",
48+" "};
sys/src/cmd/python/Demo/tix/bitmaps/rightj.xbm+6−0
@@ -0,0 +1,6 @@
1+#define rightj_width 16
2+#define rightj_height 16
3+static unsigned char rightj_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdb, 0x00, 0x00, 0x70, 0xdb,
5+ 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0xd8, 0xde, 0x00, 0x00, 0xc0, 0xdd,
6+ 0x00, 0x00, 0xa0, 0xef, 0x00, 0x00, 0xd8, 0xde};
sys/src/cmd/python/Demo/tix/bitmaps/select.xpm+52−0
@@ -0,0 +1,52 @@
1+/* XPM */
2+static char * select_xpm[] = {
3+"50 40 9 1",
4+" s None c None",
5+". c black",
6+"X c gray95",
7+"o c gray50",
8+"O c gray70",
9+"+ c navy",
10+"@ c #000080800000",
11+"# c #808000000000",
12+"$ c white",
13+" ",
14+" ",
15+" ",
16+" ",
17+" ",
18+" ",
19+" ",
20+" ",
21+" ",
22+" .............................................. ",
23+" .XXXXXXXXXXooooooooooooXXXXXXXXXXXoXXXXXXXXXX. ",
24+" .X ooOOOOOOOOOOXX oX o. ",
25+" .X ooOOOOOOOOOOXX oX o. ",
26+" .X ++++ ooOOOOOOOOOOXX ... oX @ o. ",
27+" .X +++++ ooOOOOOOOOOOXX . . oX @@@ o. ",
28+" .X +++ + ooOOOOOOOOOOXX . . oX @ @ o. ",
29+" .X + + ooOO#####OOOXX . . oX @ @ o. ",
30+" .X + + ooOO#OOO##OOXX . oX @ @ o. ",
31+" .X + + ooO##OOOO##OXX . oX @ @ o. ",
32+" .X ++ ++ ooO###OOO#OOXX . oX @ @ o. ",
33+" .X +++++++ ooO#######OOXX . oX @ @ o. ",
34+" .X + + ooO##O#OO#OOXX . oX @ @ o. ",
35+" .X + ++ ooO##OOOOO#OXX . . oX @ @ o. ",
36+" .X + + ooOO#OOOOO#OXX . . oX @ @@ o. ",
37+" .X + ++ ooOO#OOOOO#OXX .... oX @@@@@ o. ",
38+" .X ooOO######OOXX oX o. ",
39+" .X ooOOOOOOOOOOXX $oX o. ",
40+" .XoooooooooooXXXXXXXXXXXoooooooooooXooooooooo. ",
41+" .............................................. ",
42+" ",
43+" ",
44+" ",
45+" ",
46+" ",
47+" ",
48+" ",
49+" ",
50+" ",
51+" ",
52+" "};
sys/src/cmd/python/Demo/tix/bitmaps/tix.gif+0−0

Binary file not shown.

sys/src/cmd/python/Demo/tix/bitmaps/underline.xbm+6−0
@@ -0,0 +1,6 @@
1+#define underline_width 16
2+#define underline_height 16
3+static unsigned char underline_bits[] = {
4+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x38, 0x1c,
5+ 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c, 0x70, 0x0e,
6+ 0xf0, 0x0f, 0xe0, 0x07, 0x00, 0x00, 0xf8, 0x1f};
sys/src/cmd/python/Demo/tix/grid.py+28−0
@@ -0,0 +1,28 @@
1+###
2+import Tix as tk
3+from pprint import pprint
4+
5+r= tk.Tk()
6+r.title("test")
7+
8+l=tk.Label(r, name="a_label")
9+l.pack()
10+
11+class MyGrid(tk.Grid):
12+ def __init__(self, *args, **kwargs):
13+ kwargs['editnotify']= self.editnotify
14+ tk.Grid.__init__(self, *args, **kwargs)
15+ def editnotify(self, x, y):
16+ return True
17+
18+g = MyGrid(r, name="a_grid",
19+selectunit="cell")
20+g.pack(fill=tk.BOTH)
21+for x in xrange(5):
22+ for y in xrange(5):
23+ g.set(x,y,text=str((x,y)))
24+
25+c = tk.Button(r, text="Close", command=r.destroy)
26+c.pack()
27+
28+tk.mainloop()
sys/src/cmd/python/Demo/tix/samples/Balloon.py+68−0
@@ -0,0 +1,68 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: Balloon.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixBalloon widget, which provides
14+# a interesting way to give help tips about elements in your user interface.
15+# Your can display the help message in a "balloon" and a status bar widget.
16+#
17+
18+import Tix
19+
20+TCL_ALL_EVENTS = 0
21+
22+def RunSample (root):
23+ balloon = DemoBalloon(root)
24+ balloon.mainloop()
25+ balloon.destroy()
26+
27+class DemoBalloon:
28+ def __init__(self, w):
29+ self.root = w
30+ self.exit = -1
31+
32+ z = w.winfo_toplevel()
33+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
34+
35+ status = Tix.Label(w, width=40, relief=Tix.SUNKEN, bd=1)
36+ status.pack(side=Tix.BOTTOM, fill=Tix.Y, padx=2, pady=1)
37+
38+ # Create two mysterious widgets that need balloon help
39+ button1 = Tix.Button(w, text='Something Unexpected',
40+ command=self.quitcmd)
41+ button2 = Tix.Button(w, text='Something Else Unexpected')
42+ button2['command'] = lambda w=button2: w.destroy()
43+ button1.pack(side=Tix.TOP, expand=1)
44+ button2.pack(side=Tix.TOP, expand=1)
45+
46+ # Create the balloon widget and associate it with the widgets that we want
47+ # to provide tips for:
48+ b = Tix.Balloon(w, statusbar=status)
49+
50+ b.bind_widget(button1, balloonmsg='Close Window',
51+ statusmsg='Press this button to close this window')
52+ b.bind_widget(button2, balloonmsg='Self-destruct button',
53+ statusmsg='Press this button and it will destroy itself')
54+
55+ def quitcmd (self):
56+ self.exit = 0
57+
58+ def mainloop(self):
59+ foundEvent = 1
60+ while self.exit < 0 and foundEvent > 0:
61+ foundEvent = self.root.tk.dooneevent(TCL_ALL_EVENTS)
62+
63+ def destroy (self):
64+ self.root.destroy()
65+
66+if __name__ == '__main__':
67+ root = Tix.Tk()
68+ RunSample(root)
sys/src/cmd/python/Demo/tix/samples/BtnBox.py+44−0
@@ -0,0 +1,44 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: BtnBox.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixButtonBox widget, which is a
14+# group of TK buttons. You can use it to manage the buttons in a dialog box,
15+# for example.
16+#
17+
18+import Tix
19+
20+def RunSample(w):
21+ # Create the label on the top of the dialog box
22+ #
23+ top = Tix.Label(w, padx=20, pady=10, bd=1, relief=Tix.RAISED,
24+ anchor=Tix.CENTER, text='This dialog box is\n a demonstration of the\n tixButtonBox widget')
25+
26+ # Create the button box and add a few buttons in it. Set the
27+ # -width of all the buttons to the same value so that they
28+ # appear in the same size.
29+ #
30+ # Note that the -text, -underline, -command and -width options are all
31+ # standard options of the button widgets.
32+ #
33+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
34+ box.add('ok', text='OK', underline=0, width=5,
35+ command=lambda w=w: w.destroy())
36+ box.add('close', text='Cancel', underline=0, width=5,
37+ command=lambda w=w: w.destroy())
38+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
39+ top.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
40+
41+if __name__ == '__main__':
42+ root = Tix.Tk()
43+ RunSample(root)
44+ root.mainloop()
sys/src/cmd/python/Demo/tix/samples/CmpImg.py+196−0
@@ -0,0 +1,196 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: CmpImg.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the compound images: it uses compound
14+# images to display a text string together with a pixmap inside
15+# buttons
16+#
17+
18+import Tix
19+
20+network_pixmap = """/* XPM */
21+static char * netw_xpm[] = {
22+/* width height ncolors chars_per_pixel */
23+"32 32 7 1",
24+/* colors */
25+" s None c None",
26+". c #000000000000",
27+"X c white",
28+"o c #c000c000c000",
29+"O c #404040",
30+"+ c blue",
31+"@ c red",
32+/* pixels */
33+" ",
34+" .............. ",
35+" .XXXXXXXXXXXX. ",
36+" .XooooooooooO. ",
37+" .Xo.......XoO. ",
38+" .Xo.++++o+XoO. ",
39+" .Xo.++++o+XoO. ",
40+" .Xo.++oo++XoO. ",
41+" .Xo.++++++XoO. ",
42+" .Xo.+o++++XoO. ",
43+" .Xo.++++++XoO. ",
44+" .Xo.XXXXXXXoO. ",
45+" .XooooooooooO. ",
46+" .Xo@ooo....oO. ",
47+" .............. .XooooooooooO. ",
48+" .XXXXXXXXXXXX. .XooooooooooO. ",
49+" .XooooooooooO. .OOOOOOOOOOOO. ",
50+" .Xo.......XoO. .............. ",
51+" .Xo.++++o+XoO. @ ",
52+" .Xo.++++o+XoO. @ ",
53+" .Xo.++oo++XoO. @ ",
54+" .Xo.++++++XoO. @ ",
55+" .Xo.+o++++XoO. @ ",
56+" .Xo.++++++XoO. ..... ",
57+" .Xo.XXXXXXXoO. .XXX. ",
58+" .XooooooooooO.@@@@@@.X O. ",
59+" .Xo@ooo....oO. .OOO. ",
60+" .XooooooooooO. ..... ",
61+" .XooooooooooO. ",
62+" .OOOOOOOOOOOO. ",
63+" .............. ",
64+" "};
65+"""
66+
67+hard_disk_pixmap = """/* XPM */
68+static char * drivea_xpm[] = {
69+/* width height ncolors chars_per_pixel */
70+"32 32 5 1",
71+/* colors */
72+" s None c None",
73+". c #000000000000",
74+"X c white",
75+"o c #c000c000c000",
76+"O c #800080008000",
77+/* pixels */
78+" ",
79+" ",
80+" ",
81+" ",
82+" ",
83+" ",
84+" ",
85+" ",
86+" ",
87+" .......................... ",
88+" .XXXXXXXXXXXXXXXXXXXXXXXo. ",
89+" .XooooooooooooooooooooooO. ",
90+" .Xooooooooooooooooo..oooO. ",
91+" .Xooooooooooooooooo..oooO. ",
92+" .XooooooooooooooooooooooO. ",
93+" .Xoooooooo.......oooooooO. ",
94+" .Xoo...................oO. ",
95+" .Xoooooooo.......oooooooO. ",
96+" .XooooooooooooooooooooooO. ",
97+" .XooooooooooooooooooooooO. ",
98+" .XooooooooooooooooooooooO. ",
99+" .XooooooooooooooooooooooO. ",
100+" .oOOOOOOOOOOOOOOOOOOOOOOO. ",
101+" .......................... ",
102+" ",
103+" ",
104+" ",
105+" ",
106+" ",
107+" ",
108+" ",
109+" "};
110+"""
111+
112+network_bitmap = """
113+#define netw_width 32
114+#define netw_height 32
115+static unsigned char netw_bits[] = {
116+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x02, 0x40,
117+ 0x00, 0x00, 0xfa, 0x5f, 0x00, 0x00, 0x0a, 0x50, 0x00, 0x00, 0x0a, 0x52,
118+ 0x00, 0x00, 0x0a, 0x52, 0x00, 0x00, 0x8a, 0x51, 0x00, 0x00, 0x0a, 0x50,
119+ 0x00, 0x00, 0x4a, 0x50, 0x00, 0x00, 0x0a, 0x50, 0x00, 0x00, 0x0a, 0x50,
120+ 0x00, 0x00, 0xfa, 0x5f, 0x00, 0x00, 0x02, 0x40, 0xfe, 0x7f, 0x52, 0x55,
121+ 0x02, 0x40, 0xaa, 0x6a, 0xfa, 0x5f, 0xfe, 0x7f, 0x0a, 0x50, 0xfe, 0x7f,
122+ 0x0a, 0x52, 0x80, 0x00, 0x0a, 0x52, 0x80, 0x00, 0x8a, 0x51, 0x80, 0x00,
123+ 0x0a, 0x50, 0x80, 0x00, 0x4a, 0x50, 0x80, 0x00, 0x0a, 0x50, 0xe0, 0x03,
124+ 0x0a, 0x50, 0x20, 0x02, 0xfa, 0xdf, 0x3f, 0x03, 0x02, 0x40, 0xa0, 0x02,
125+ 0x52, 0x55, 0xe0, 0x03, 0xaa, 0x6a, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
126+ 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
127+"""
128+
129+hard_disk_bitmap = """
130+#define drivea_width 32
131+#define drivea_height 32
132+static unsigned char drivea_bits[] = {
133+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136+ 0xf8, 0xff, 0xff, 0x1f, 0x08, 0x00, 0x00, 0x18, 0xa8, 0xaa, 0xaa, 0x1a,
137+ 0x48, 0x55, 0xd5, 0x1d, 0xa8, 0xaa, 0xaa, 0x1b, 0x48, 0x55, 0x55, 0x1d,
138+ 0xa8, 0xfa, 0xaf, 0x1a, 0xc8, 0xff, 0xff, 0x1d, 0xa8, 0xfa, 0xaf, 0x1a,
139+ 0x48, 0x55, 0x55, 0x1d, 0xa8, 0xaa, 0xaa, 0x1a, 0x48, 0x55, 0x55, 0x1d,
140+ 0xa8, 0xaa, 0xaa, 0x1a, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f,
141+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
144+"""
145+
146+def RunSample(w):
147+ w.img0 = Tix.Image('pixmap', data=network_pixmap)
148+ if not w.img0:
149+ w.img0 = Tix.Image('bitmap', data=network_bitmap)
150+ w.img1 = Tix.Image('pixmap', data=hard_disk_pixmap)
151+ if not w.img0:
152+ w.img1 = Tix.Image('bitmap', data=hard_disk_bitmap)
153+
154+ hdd = Tix.Button(w, padx=4, pady=1, width=120)
155+ net = Tix.Button(w, padx=4, pady=1, width=120)
156+
157+ # Create the first image: we create a line, then put a string,
158+ # a space and a image into this line, from left to right.
159+ # The result: we have a one-line image that consists of three
160+ # individual items
161+ #
162+ # The tk.calls should be methods in Tix ...
163+ w.hdd_img = Tix.Image('compound', window=hdd)
164+ w.hdd_img.tk.call(str(w.hdd_img), 'add', 'line')
165+ w.hdd_img.tk.call(str(w.hdd_img), 'add', 'text', '-text', 'Hard Disk',
166+ '-underline', '0')
167+ w.hdd_img.tk.call(str(w.hdd_img), 'add', 'space', '-width', '7')
168+ w.hdd_img.tk.call(str(w.hdd_img), 'add', 'image', '-image', w.img1)
169+
170+ # Put this image into the first button
171+ #
172+ hdd['image'] = w.hdd_img
173+
174+ # Next button
175+ w.net_img = Tix.Image('compound', window=net)
176+ w.net_img.tk.call(str(w.net_img), 'add', 'line')
177+ w.net_img.tk.call(str(w.net_img), 'add', 'text', '-text', 'Network',
178+ '-underline', '0')
179+ w.net_img.tk.call(str(w.net_img), 'add', 'space', '-width', '7')
180+ w.net_img.tk.call(str(w.net_img), 'add', 'image', '-image', w.img0)
181+
182+ # Put this image into the first button
183+ #
184+ net['image'] = w.net_img
185+
186+ close = Tix.Button(w, pady=1, text='Close',
187+ command=lambda w=w: w.destroy())
188+
189+ hdd.pack(side=Tix.LEFT, padx=10, pady=10, fill=Tix.Y, expand=1)
190+ net.pack(side=Tix.LEFT, padx=10, pady=10, fill=Tix.Y, expand=1)
191+ close.pack(side=Tix.LEFT, padx=10, pady=10, fill=Tix.Y, expand=1)
192+
193+if __name__ == '__main__':
194+ root = Tix.Tk()
195+ RunSample(root)
196+ root.mainloop()
sys/src/cmd/python/Demo/tix/samples/ComboBox.py+102−0
@@ -0,0 +1,102 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: ComboBox.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixComboBox widget, which is close
14+# to the MS Window Combo Box control.
15+#
16+import Tix
17+
18+def RunSample(w):
19+ global demo_month, demo_year
20+
21+ top = Tix.Frame(w, bd=1, relief=Tix.RAISED)
22+
23+ demo_month = Tix.StringVar()
24+ demo_year = Tix.StringVar()
25+
26+ # $w.top.a is a drop-down combo box. It is not editable -- who wants
27+ # to invent new months?
28+ #
29+ # [Hint] The -options switch sets the options of the subwidgets.
30+ # [Hint] We set the label.width subwidget option of both comboboxes to
31+ # be 10 so that their labels appear to be aligned.
32+ #
33+ a = Tix.ComboBox(top, label="Month: ", dropdown=1,
34+ command=select_month, editable=0, variable=demo_month,
35+ options='listbox.height 6 label.width 10 label.anchor e')
36+
37+ # $w.top.b is a non-drop-down combo box. It is not editable: we provide
38+ # four choices for the user, but he can enter an alternative year if he
39+ # wants to.
40+ #
41+ # [Hint] Use the padY and anchor options of the label subwidget to
42+ # align the label with the entry subwidget.
43+ # [Hint] Notice that you should use padY (the NAME of the option) and not
44+ # pady (the SWITCH of the option).
45+ #
46+ b = Tix.ComboBox(top, label="Year: ", dropdown=0,
47+ command=select_year, editable=1, variable=demo_year,
48+ options='listbox.height 4 label.padY 5 label.width 10 label.anchor ne')
49+
50+ a.pack(side=Tix.TOP, anchor=Tix.W)
51+ b.pack(side=Tix.TOP, anchor=Tix.W)
52+
53+ a.insert(Tix.END, 'January')
54+ a.insert(Tix.END, 'February')
55+ a.insert(Tix.END, 'March')
56+ a.insert(Tix.END, 'April')
57+ a.insert(Tix.END, 'May')
58+ a.insert(Tix.END, 'June')
59+ a.insert(Tix.END, 'July')
60+ a.insert(Tix.END, 'August')
61+ a.insert(Tix.END, 'September')
62+ a.insert(Tix.END, 'October')
63+ a.insert(Tix.END, 'November')
64+ a.insert(Tix.END, 'December')
65+
66+ b.insert(Tix.END, '1992')
67+ b.insert(Tix.END, '1993')
68+ b.insert(Tix.END, '1994')
69+ b.insert(Tix.END, '1995')
70+ b.insert(Tix.END, '1996')
71+
72+ # Use "tixSetSilent" to set the values of the combo box if you
73+ # don't want your -command procedures (cbx:select_month and
74+ # cbx:select_year) to be called.
75+ #
76+ a.set_silent('January')
77+ b.set_silent('1995')
78+
79+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
80+ box.add('ok', text='Ok', underline=0, width=6,
81+ command=lambda w=w: ok_command(w))
82+ box.add('cancel', text='Cancel', underline=0, width=6,
83+ command=lambda w=w: w.destroy())
84+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
85+ top.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
86+
87+def select_month(event=None):
88+ # tixDemo:Status "Month = %s" % demo_month.get()
89+ pass
90+
91+def select_year(event=None):
92+ # tixDemo:Status "Year = %s" % demo_year.get()
93+ pass
94+
95+def ok_command(w):
96+ # tixDemo:Status "Month = %s, Year= %s" % (demo_month.get(), demo_year.get())
97+ w.destroy()
98+
99+if __name__ == '__main__':
100+ root = Tix.Tk()
101+ RunSample(root)
102+ root.mainloop()
sys/src/cmd/python/Demo/tix/samples/Control.py+122−0
@@ -0,0 +1,122 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: Control.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixControl widget -- it is an
14+# entry widget with up/down arrow buttons. You can use the arrow buttons
15+# to adjust the value inside the entry widget.
16+#
17+# This example program uses three Control widgets. One lets you select
18+# integer values; one lets you select floating point values and the last
19+# one lets you select a few names.
20+
21+import Tix
22+
23+TCL_ALL_EVENTS = 0
24+
25+def RunSample (root):
26+ control = DemoControl(root)
27+ control.mainloop()
28+ control.destroy()
29+
30+class DemoControl:
31+ def __init__(self, w):
32+ self.root = w
33+ self.exit = -1
34+
35+ global demo_maker, demo_thrust, demo_num_engines
36+
37+ demo_maker = Tix.StringVar()
38+ demo_thrust = Tix.DoubleVar()
39+ demo_num_engines = Tix.IntVar()
40+ demo_maker.set('P&W')
41+ demo_thrust.set(20000.0)
42+ demo_num_engines.set(2)
43+
44+ top = Tix.Frame(w, bd=1, relief=Tix.RAISED)
45+
46+ # $w.top.a allows only integer values
47+ #
48+ # [Hint] The -options switch sets the options of the subwidgets.
49+ # [Hint] We set the label.width subwidget option of the Controls to
50+ # be 16 so that their labels appear to be aligned.
51+ #
52+ a = Tix.Control(top, label='Number of Engines: ', integer=1,
53+ variable=demo_num_engines, min=1, max=4,
54+ options='entry.width 10 label.width 20 label.anchor e')
55+
56+ b = Tix.Control(top, label='Thrust: ', integer=0,
57+ min='10000.0', max='60000.0', step=500,
58+ variable=demo_thrust,
59+ options='entry.width 10 label.width 20 label.anchor e')
60+
61+ c = Tix.Control(top, label='Engine Maker: ', value='P&W',
62+ variable=demo_maker,
63+ options='entry.width 10 label.width 20 label.anchor e')
64+
65+ # We can't define these in the init because the widget 'c' doesn't
66+ # exist yet and we need to reference it
67+ c['incrcmd'] = lambda w=c: adjust_maker(w, 1)
68+ c['decrcmd'] = lambda w=c: adjust_maker(w, -1)
69+ c['validatecmd'] = lambda w=c: validate_maker(w)
70+
71+ a.pack(side=Tix.TOP, anchor=Tix.W)
72+ b.pack(side=Tix.TOP, anchor=Tix.W)
73+ c.pack(side=Tix.TOP, anchor=Tix.W)
74+
75+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
76+ box.add('ok', text='Ok', underline=0, width=6,
77+ command=self.okcmd)
78+ box.add('cancel', text='Cancel', underline=0, width=6,
79+ command=self.quitcmd)
80+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
81+ top.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
82+
83+ def okcmd (self):
84+ # tixDemo:Status "Selected %d of %s engines each of thrust %d", (demo_num_engines.get(), demo_maker.get(), demo_thrust.get())
85+ self.quitcmd()
86+
87+ def quitcmd (self):
88+ self.exit = 0
89+
90+ def mainloop(self):
91+ while self.exit < 0:
92+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
93+
94+ def destroy (self):
95+ self.root.destroy()
96+
97+maker_list = ['P&W', 'GE', 'Rolls Royce']
98+
99+def adjust_maker(w, inc):
100+ i = maker_list.index(demo_maker.get())
101+ i = i + inc
102+ if i >= len(maker_list):
103+ i = 0
104+ elif i < 0:
105+ i = len(maker_list) - 1
106+
107+ # In Tcl/Tix we should return the string maker_list[i]. We can't
108+ # do that in Tkinter so we set the global variable. (This works).
109+ demo_maker.set(maker_list[i])
110+
111+def validate_maker(w):
112+ try:
113+ i = maker_list.index(demo_maker.get())
114+ except ValueError:
115+ # Works here though. Why ? Beats me.
116+ return maker_list[0]
117+ # Works here though. Why ? Beats me.
118+ return maker_list[i]
119+
120+if __name__ == '__main__':
121+ root = Tix.Tk()
122+ RunSample(root)
sys/src/cmd/python/Demo/tix/samples/DirList.py+131−0
@@ -0,0 +1,131 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: DirList.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program using tixwish.
12+
13+# This file demonstrates the use of the tixDirList widget -- you can
14+# use it for the user to select a directory. For example, an installation
15+# program can use the tixDirList widget to ask the user to select the
16+# installation directory for an application.
17+#
18+
19+import Tix, os, copy
20+from Tkconstants import *
21+
22+TCL_ALL_EVENTS = 0
23+
24+def RunSample (root):
25+ dirlist = DemoDirList(root)
26+ dirlist.mainloop()
27+ dirlist.destroy()
28+
29+class DemoDirList:
30+ def __init__(self, w):
31+ self.root = w
32+ self.exit = -1
33+
34+ z = w.winfo_toplevel()
35+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
36+
37+ # Create the tixDirList and the tixLabelEntry widgets on the on the top
38+ # of the dialog box
39+
40+ # bg = root.tk.eval('tix option get bg')
41+ # adding bg=bg crashes Windows pythonw tk8.3.3 Python 2.1.0
42+
43+ top = Tix.Frame( w, relief=RAISED, bd=1)
44+
45+ # Create the DirList widget. By default it will show the current
46+ # directory
47+ #
48+ #
49+ top.dir = Tix.DirList(top)
50+ top.dir.hlist['width'] = 40
51+
52+ # When the user presses the ".." button, the selected directory
53+ # is "transferred" into the entry widget
54+ #
55+ top.btn = Tix.Button(top, text = " >> ", pady = 0)
56+
57+ # We use a LabelEntry to hold the installation directory. The user
58+ # can choose from the DirList widget, or he can type in the directory
59+ # manually
60+ #
61+ top.ent = Tix.LabelEntry(top, label="Installation Directory:",
62+ labelside = 'top',
63+ options = '''
64+ entry.width 40
65+ label.anchor w
66+ ''')
67+
68+ font = self.root.tk.eval('tix option get fixed_font')
69+ # font = self.root.master.tix_option_get('fixed_font')
70+ top.ent.entry['font'] = font
71+
72+ self.dlist_dir = copy.copy(os.curdir)
73+ # This should work setting the entry's textvariable
74+ top.ent.entry['textvariable'] = self.dlist_dir
75+ top.btn['command'] = lambda dir=top.dir, ent=top.ent, self=self: \
76+ self.copy_name(dir,ent)
77+
78+ # top.ent.entry.insert(0,'tix'+repr(self))
79+ top.ent.entry.bind('<Return>', lambda self=self: self.okcmd () )
80+
81+ top.pack( expand='yes', fill='both', side=TOP)
82+ top.dir.pack( expand=1, fill=BOTH, padx=4, pady=4, side=LEFT)
83+ top.btn.pack( anchor='s', padx=4, pady=4, side=LEFT)
84+ top.ent.pack( expand=1, fill=X, anchor='s', padx=4, pady=4, side=LEFT)
85+
86+ # Use a ButtonBox to hold the buttons.
87+ #
88+ box = Tix.ButtonBox (w, orientation='horizontal')
89+ box.add ('ok', text='Ok', underline=0, width=6,
90+ command = lambda self=self: self.okcmd () )
91+ box.add ('cancel', text='Cancel', underline=0, width=6,
92+ command = lambda self=self: self.quitcmd () )
93+
94+ box.pack( anchor='s', fill='x', side=BOTTOM)
95+
96+ def copy_name (self, dir, ent):
97+ # This should work as it is the entry's textvariable
98+ self.dlist_dir = dir.cget('value')
99+ # but it isn't so I'll do it manually
100+ ent.entry.delete(0,'end')
101+ ent.entry.insert(0, self.dlist_dir)
102+
103+ def okcmd (self):
104+ # tixDemo:Status "You have selected the directory" + self.dlist_dir
105+ self.quitcmd()
106+
107+ def quitcmd (self):
108+ self.exit = 0
109+
110+ def mainloop(self):
111+ while self.exit < 0:
112+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
113+
114+ def destroy (self):
115+ self.root.destroy()
116+
117+# This "if" statement makes it possible to run this script file inside or
118+# outside of the main demo program "tixwidgets.py".
119+#
120+if __name__== '__main__' :
121+ import tkMessageBox, traceback
122+
123+ try:
124+ root=Tix.Tk()
125+ RunSample(root)
126+ except:
127+ t, v, tb = sys.exc_info()
128+ text = "Error running the demo script:\n"
129+ for line in traceback.format_exception(t,v,tb):
130+ text = text + line + '\n'
131+ d = tkMessageBox.showerror ( 'Tix Demo Error', text)
sys/src/cmd/python/Demo/tix/samples/DirTree.py+117−0
@@ -0,0 +1,117 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: DirTree.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program using tixwish.
12+
13+# This file demonstrates the use of the tixDirTree widget -- you can
14+# use it for the user to select a directory. For example, an installation
15+# program can use the tixDirTree widget to ask the user to select the
16+# installation directory for an application.
17+#
18+
19+import Tix, os, copy
20+from Tkconstants import *
21+
22+TCL_ALL_EVENTS = 0
23+
24+def RunSample (root):
25+ dirtree = DemoDirTree(root)
26+ dirtree.mainloop()
27+ dirtree.destroy()
28+
29+class DemoDirTree:
30+ def __init__(self, w):
31+ self.root = w
32+ self.exit = -1
33+
34+ z = w.winfo_toplevel()
35+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
36+
37+ # Create the tixDirTree and the tixLabelEntry widgets on the on the top
38+ # of the dialog box
39+
40+ # bg = root.tk.eval('tix option get bg')
41+ # adding bg=bg crashes Windows pythonw tk8.3.3 Python 2.1.0
42+
43+ top = Tix.Frame( w, relief=RAISED, bd=1)
44+
45+ # Create the DirTree widget. By default it will show the current
46+ # directory
47+ #
48+ #
49+ top.dir = Tix.DirTree(top)
50+ top.dir.hlist['width'] = 40
51+
52+ # When the user presses the ".." button, the selected directory
53+ # is "transferred" into the entry widget
54+ #
55+ top.btn = Tix.Button(top, text = " >> ", pady = 0)
56+
57+ # We use a LabelEntry to hold the installation directory. The user
58+ # can choose from the DirTree widget, or he can type in the directory
59+ # manually
60+ #
61+ top.ent = Tix.LabelEntry(top, label="Installation Directory:",
62+ labelside = 'top',
63+ options = '''
64+ entry.width 40
65+ label.anchor w
66+ ''')
67+
68+ self.dlist_dir = copy.copy(os.curdir)
69+ top.ent.entry['textvariable'] = self.dlist_dir
70+ top.btn['command'] = lambda dir=top.dir, ent=top.ent, self=self: \
71+ self.copy_name(dir,ent)
72+
73+ top.ent.entry.bind('<Return>', lambda self=self: self.okcmd () )
74+
75+ top.pack( expand='yes', fill='both', side=TOP)
76+ top.dir.pack( expand=1, fill=BOTH, padx=4, pady=4, side=LEFT)
77+ top.btn.pack( anchor='s', padx=4, pady=4, side=LEFT)
78+ top.ent.pack( expand=1, fill=X, anchor='s', padx=4, pady=4, side=LEFT)
79+
80+ # Use a ButtonBox to hold the buttons.
81+ #
82+ box = Tix.ButtonBox (w, orientation='horizontal')
83+ box.add ('ok', text='Ok', underline=0, width=6,
84+ command = lambda self=self: self.okcmd () )
85+ box.add ('cancel', text='Cancel', underline=0, width=6,
86+ command = lambda self=self: self.quitcmd () )
87+
88+ box.pack( anchor='s', fill='x', side=BOTTOM)
89+
90+ def copy_name (self, dir, ent):
91+ # This should work as it is the entry's textvariable
92+ self.dlist_dir = dir.cget('value')
93+ # but it isn't so I'll do it manually
94+ ent.entry.delete(0,'end')
95+ ent.entry.insert(0, self.dlist_dir)
96+
97+ def okcmd (self):
98+ # tixDemo:Status "You have selected the directory" + self.dlist_dir
99+ self.quitcmd()
100+
101+ def quitcmd (self):
102+ # tixDemo:Status "You have selected the directory" + self.dlist_dir
103+ self.exit = 0
104+
105+ def mainloop(self):
106+ while self.exit < 0:
107+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
108+
109+ def destroy (self):
110+ self.root.destroy()
111+
112+# This "if" statement makes it possible to run this script file inside or
113+# outside of the main demo program "tixwidgets.py".
114+#
115+if __name__== '__main__' :
116+ root=Tix.Tk()
117+ RunSample(root)
sys/src/cmd/python/Demo/tix/samples/NoteBook.py+119−0
@@ -0,0 +1,119 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: NoteBook.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixNoteBook widget, which allows
14+# you to lay out your interface using a "notebook" metaphore
15+#
16+import Tix
17+
18+def RunSample(w):
19+ global root
20+ root = w
21+
22+ # We use these options to set the sizes of the subwidgets inside the
23+ # notebook, so that they are well-aligned on the screen.
24+ prefix = Tix.OptionName(w)
25+ if prefix:
26+ prefix = '*'+prefix
27+ else:
28+ prefix = ''
29+ w.option_add(prefix+'*TixControl*entry.width', 10)
30+ w.option_add(prefix+'*TixControl*label.width', 18)
31+ w.option_add(prefix+'*TixControl*label.anchor', Tix.E)
32+ w.option_add(prefix+'*TixNoteBook*tagPadX', 8)
33+
34+ # Create the notebook widget and set its backpagecolor to gray.
35+ # Note that the -backpagecolor option belongs to the "nbframe"
36+ # subwidget.
37+ nb = Tix.NoteBook(w, name='nb', ipadx=6, ipady=6)
38+ nb['bg'] = 'gray'
39+ nb.nbframe['backpagecolor'] = 'gray'
40+
41+ # Create the two tabs on the notebook. The -underline option
42+ # puts a underline on the first character of the labels of the tabs.
43+ # Keyboard accelerators will be defined automatically according
44+ # to the underlined character.
45+ nb.add('hard_disk', label="Hard Disk", underline=0)
46+ nb.add('network', label="Network", underline=0)
47+
48+ nb.pack(expand=1, fill=Tix.BOTH, padx=5, pady=5 ,side=Tix.TOP)
49+
50+ #----------------------------------------
51+ # Create the first page
52+ #----------------------------------------
53+ # Create two frames: one for the common buttons, one for the
54+ # other widgets
55+ #
56+ tab=nb.hard_disk
57+ f = Tix.Frame(tab)
58+ common = Tix.Frame(tab)
59+
60+ f.pack(side=Tix.LEFT, padx=2, pady=2, fill=Tix.BOTH, expand=1)
61+ common.pack(side=Tix.RIGHT, padx=2, fill=Tix.Y)
62+
63+ a = Tix.Control(f, value=12, label='Access time: ')
64+ w = Tix.Control(f, value=400, label='Write Throughput: ')
65+ r = Tix.Control(f, value=400, label='Read Throughput: ')
66+ c = Tix.Control(f, value=1021, label='Capacity: ')
67+
68+ a.pack(side=Tix.TOP, padx=20, pady=2)
69+ w.pack(side=Tix.TOP, padx=20, pady=2)
70+ r.pack(side=Tix.TOP, padx=20, pady=2)
71+ c.pack(side=Tix.TOP, padx=20, pady=2)
72+
73+ # Create the common buttons
74+ createCommonButtons(common)
75+
76+ #----------------------------------------
77+ # Create the second page
78+ #----------------------------------------
79+
80+ tab = nb.network
81+
82+ f = Tix.Frame(tab)
83+ common = Tix.Frame(tab)
84+
85+ f.pack(side=Tix.LEFT, padx=2, pady=2, fill=Tix.BOTH, expand=1)
86+ common.pack(side=Tix.RIGHT, padx=2, fill=Tix.Y)
87+
88+ a = Tix.Control(f, value=12, label='Access time: ')
89+ w = Tix.Control(f, value=400, label='Write Throughput: ')
90+ r = Tix.Control(f, value=400, label='Read Throughput: ')
91+ c = Tix.Control(f, value=1021, label='Capacity: ')
92+ u = Tix.Control(f, value=10, label='Users: ')
93+
94+ a.pack(side=Tix.TOP, padx=20, pady=2)
95+ w.pack(side=Tix.TOP, padx=20, pady=2)
96+ r.pack(side=Tix.TOP, padx=20, pady=2)
97+ c.pack(side=Tix.TOP, padx=20, pady=2)
98+ u.pack(side=Tix.TOP, padx=20, pady=2)
99+
100+ createCommonButtons(common)
101+
102+def doDestroy():
103+ global root
104+ root.destroy()
105+
106+def createCommonButtons(master):
107+ ok = Tix.Button(master, name='ok', text='OK', width=6,
108+ command=doDestroy)
109+ cancel = Tix.Button(master, name='cancel',
110+ text='Cancel', width=6,
111+ command=doDestroy)
112+
113+ ok.pack(side=Tix.TOP, padx=2, pady=2)
114+ cancel.pack(side=Tix.TOP, padx=2, pady=2)
115+
116+if __name__ == '__main__':
117+ root = Tix.Tk()
118+ RunSample(root)
119+ root.mainloop()
sys/src/cmd/python/Demo/tix/samples/OptMenu.py+68−0
@@ -0,0 +1,68 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: OptMenu.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixOptionMenu widget -- you can
14+# use it for the user to choose from a fixed set of options
15+#
16+import Tix
17+
18+options = {'text':'Plain Text', 'post':'PostScript', 'html':'HTML',
19+ 'tex':'LaTeX', 'rtf':'Rich Text Format'}
20+
21+def RunSample(w):
22+ global demo_opt_from, demo_opt_to
23+
24+ demo_opt_from = Tix.StringVar()
25+ demo_opt_to = Tix.StringVar()
26+
27+ top = Tix.Frame(w, bd=1, relief=Tix.RAISED)
28+
29+ from_file = Tix.OptionMenu(top, label="From File Format : ",
30+ variable=demo_opt_from,
31+ options = 'label.width 19 label.anchor e menubutton.width 15')
32+
33+ to_file = Tix.OptionMenu(top, label="To File Format : ",
34+ variable=demo_opt_to,
35+ options='label.width 19 label.anchor e menubutton.width 15')
36+
37+ # Add the available options to the two OptionMenu widgets
38+ #
39+ # [Hint] You have to add the options first before you set the
40+ # global variables "demo_opt_from" and "demo_opt_to". Otherwise
41+ # the OptionMenu widget will complain about "unknown options"!
42+ #
43+ for opt in options.keys():
44+ from_file.add_command(opt, label=options[opt])
45+ to_file.add_command(opt, label=options[opt])
46+
47+ demo_opt_from.set('html')
48+ demo_opt_to.set('post')
49+
50+ from_file.pack(side=Tix.TOP, anchor=Tix.W, pady=3, padx=6)
51+ to_file.pack(side=Tix.TOP, anchor=Tix.W, pady=3, padx=6)
52+
53+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
54+ box.add('ok', text='Ok', underline=0, width=6,
55+ command=lambda w=w: ok_command(w))
56+ box.add('cancel', text='Cancel', underline=0, width=6,
57+ command=lambda w=w: w.destroy())
58+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
59+ top.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
60+
61+def ok_command(w):
62+ # tixDemo:Status "Convert file from %s to %s" % ( demo_opt_from.get(), demo_opt_to.get())
63+ w.destroy()
64+
65+if __name__ == '__main__':
66+ root = Tix.Tk()
67+ RunSample(root)
68+ root.mainloop()
sys/src/cmd/python/Demo/tix/samples/PanedWin.py+98−0
@@ -0,0 +1,98 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: PanedWin.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates the use of the tixPanedWindow widget. This program
14+# is a dummy news reader: the user can adjust the sizes of the list
15+# of artical names and the size of the text widget that shows the body
16+# of the article.
17+
18+import Tix
19+
20+TCL_ALL_EVENTS = 0
21+
22+def RunSample (root):
23+ panedwin = DemoPanedwin(root)
24+ panedwin.mainloop()
25+ panedwin.destroy()
26+
27+class DemoPanedwin:
28+ def __init__(self, w):
29+ self.root = w
30+ self.exit = -1
31+
32+ z = w.winfo_toplevel()
33+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
34+
35+ group = Tix.LabelEntry(w, label='Newsgroup:', options='entry.width 25')
36+ group.entry.insert(0,'comp.lang.python')
37+ pane = Tix.PanedWindow(w, orientation='vertical')
38+
39+ p1 = pane.add('list', min=70, size=100)
40+ p2 = pane.add('text', min=70)
41+ list = Tix.ScrolledListBox(p1)
42+ list.listbox['width'] = 80
43+ list.listbox['height'] = 5
44+ text = Tix.ScrolledText(p2)
45+ text.text['width'] = 80
46+ text.text['height'] = 20
47+
48+ list.listbox.insert(Tix.END, " 12324 Re: Tkinter is good for your health")
49+ list.listbox.insert(Tix.END, "+ 12325 Re: Tkinter is good for your health")
50+ list.listbox.insert(Tix.END, "+ 12326 Re: Tix is even better for your health (Was: Tkinter is good...)")
51+ list.listbox.insert(Tix.END, " 12327 Re: Tix is even better for your health (Was: Tkinter is good...)")
52+ list.listbox.insert(Tix.END, "+ 12328 Re: Tix is even better for your health (Was: Tkinter is good...)")
53+ list.listbox.insert(Tix.END, " 12329 Re: Tix is even better for your health (Was: Tkinter is good...)")
54+ list.listbox.insert(Tix.END, "+ 12330 Re: Tix is even better for your health (Was: Tkinter is good...)")
55+
56+ text.text['bg'] = list.listbox['bg']
57+ text.text['wrap'] = 'none'
58+ text.text.insert(Tix.END, """
59+ Mon, 19 Jun 1995 11:39:52 comp.lang.python Thread 34 of 220
60+ Lines 353 A new way to put text and bitmaps together iNo responses
61+ ioi@blue.seas.upenn.edu Ioi K. Lam at University of Pennsylvania
62+
63+ Hi,
64+
65+ I have implemented a new image type called "compound". It allows you
66+ to glue together a bunch of bitmaps, images and text strings together
67+ to form a bigger image. Then you can use this image with widgets that
68+ support the -image option. For example, you can display a text string string
69+ together with a bitmap, at the same time, inside a TK button widget.
70+ """)
71+ text.text['state'] = 'disabled'
72+
73+ list.pack(expand=1, fill=Tix.BOTH, padx=4, pady=6)
74+ text.pack(expand=1, fill=Tix.BOTH, padx=4, pady=6)
75+
76+ group.pack(side=Tix.TOP, padx=3, pady=3, fill=Tix.BOTH)
77+ pane.pack(side=Tix.TOP, padx=3, pady=3, fill=Tix.BOTH, expand=1)
78+
79+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
80+ box.add('ok', text='Ok', underline=0, width=6,
81+ command=self.quitcmd)
82+ box.add('cancel', text='Cancel', underline=0, width=6,
83+ command=self.quitcmd)
84+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
85+
86+ def quitcmd (self):
87+ self.exit = 0
88+
89+ def mainloop(self):
90+ while self.exit < 0:
91+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
92+
93+ def destroy (self):
94+ self.root.destroy()
95+
96+if __name__ == '__main__':
97+ root = Tix.Tk()
98+ RunSample(root)
sys/src/cmd/python/Demo/tix/samples/PopMenu.py+57−0
@@ -0,0 +1,57 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: PopMenu.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program using tixwish.
12+
13+# This file demonstrates the use of the tixPopupMenu widget.
14+#
15+import Tix
16+
17+def RunSample(w):
18+ # We create the frame and the button, then we'll bind the PopupMenu
19+ # to both widgets. The result is, when you press the right mouse
20+ # button over $w.top or $w.top.but, the PopupMenu will come up.
21+ #
22+ top = Tix.Frame(w, relief=Tix.RAISED, bd=1)
23+ but = Tix.Button(top, text='Press the right mouse button over this button or its surrounding area')
24+ but.pack(expand=1, fill=Tix.BOTH, padx=50, pady=50)
25+
26+ p = Tix.PopupMenu(top, title='Popup Test')
27+ p.bind_widget(top)
28+ p.bind_widget(but)
29+
30+ # Set the entries inside the PopupMenu widget.
31+ # [Hint] You have to manipulate the "menu" subwidget.
32+ # $w.top.p itself is NOT a menu widget.
33+ # [Hint] Watch carefully how the sub-menu is created
34+ #
35+ p.menu.add_command(label='Desktop', underline=0)
36+ p.menu.add_command(label='Select', underline=0)
37+ p.menu.add_command(label='Find', underline=0)
38+ p.menu.add_command(label='System', underline=1)
39+ p.menu.add_command(label='Help', underline=0)
40+ m1 = Tix.Menu(p.menu)
41+ m1.add_command(label='Hello')
42+ p.menu.add_cascade(label='More', menu=m1)
43+
44+ but.pack(side=Tix.TOP, padx=40, pady=50)
45+
46+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
47+ box.add('ok', text='Ok', underline=0, width=6,
48+ command=lambda w=w: w.destroy())
49+ box.add('cancel', text='Cancel', underline=0, width=6,
50+ command=lambda w=w: w.destroy())
51+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
52+ top.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
53+
54+if __name__ == '__main__':
55+ root = Tix.Tk()
56+ RunSample(root)
57+ root.mainloop()
sys/src/cmd/python/Demo/tix/samples/SHList1.py+131−0
@@ -0,0 +1,131 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: SHList1.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program using tixwish.
12+
13+# This file demonstrates the use of the tixScrolledHList widget.
14+#
15+
16+import Tix
17+
18+TCL_ALL_EVENTS = 0
19+
20+def RunSample (root):
21+ shlist = DemoSHList(root)
22+ shlist.mainloop()
23+ shlist.destroy()
24+
25+class DemoSHList:
26+ def __init__(self, w):
27+ self.root = w
28+ self.exit = -1
29+
30+ z = w.winfo_toplevel()
31+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
32+
33+ # We create the frame and the ScrolledHList widget
34+ # at the top of the dialog box
35+ #
36+ top = Tix.Frame( w, relief=Tix.RAISED, bd=1)
37+
38+ # Put a simple hierachy into the HList (two levels). Use colors and
39+ # separator widgets (frames) to make the list look fancy
40+ #
41+ top.a = Tix.ScrolledHList(top)
42+ top.a.pack( expand=1, fill=Tix.BOTH, padx=10, pady=10, side=Tix.TOP)
43+
44+ # This is our little relational database
45+ #
46+ bosses = [
47+ ('jeff', 'Jeff Waxman'),
48+ ('john', 'John Lee'),
49+ ('peter', 'Peter Kenson')
50+ ]
51+
52+ employees = [
53+ ('alex', 'john', 'Alex Kellman'),
54+ ('alan', 'john', 'Alan Adams'),
55+ ('andy', 'peter', 'Andreas Crawford'),
56+ ('doug', 'jeff', 'Douglas Bloom'),
57+ ('jon', 'peter', 'Jon Baraki'),
58+ ('chris', 'jeff', 'Chris Geoffrey'),
59+ ('chuck', 'jeff', 'Chuck McLean')
60+ ]
61+
62+ hlist=top.a.hlist
63+
64+ # Let configure the appearance of the HList subwidget
65+ #
66+ hlist.config( separator='.', width=25, drawbranch=0, indent=10)
67+
68+ count=0
69+ for boss,name in bosses :
70+ if count :
71+ f=Tix.Frame(hlist, name='sep%d' % count, height=2, width=150,
72+ bd=2, relief=Tix.SUNKEN )
73+
74+ hlist.add_child( itemtype=Tix.WINDOW,
75+ window=f, state=Tix.DISABLED )
76+
77+ hlist.add(boss, itemtype=Tix.TEXT, text=name)
78+ count = count+1
79+
80+
81+ for person,boss,name in employees :
82+ # '.' is the separator character we chose above
83+ #
84+ key= boss + '.' + person
85+ # ^^^^ ^^^^^^
86+ # parent entryPath / child's name
87+
88+ hlist.add( key, text=name )
89+
90+ # [Hint] Make sure the keys (e.g. 'boss.person') you choose
91+ # are unique names. If you cannot be sure of this (because of
92+ # the structure of your database, e.g.) you can use the
93+ # "add_child" command instead:
94+ #
95+ # hlist.addchild( boss, text=name)
96+ # ^^^^
97+ # parent entryPath
98+
99+
100+ # Use a ButtonBox to hold the buttons.
101+ #
102+ box= Tix.ButtonBox(top, orientation=Tix.HORIZONTAL )
103+ box.add( 'ok', text='Ok', underline=0, width=6,
104+ command = self.okcmd)
105+
106+ box.add( 'cancel', text='Cancel', underline=0, width=6,
107+ command = self.quitcmd)
108+
109+ box.pack( side=Tix.BOTTOM, fill=Tix.X)
110+ top.pack( side=Tix.TOP, fill=Tix.BOTH, expand=1 )
111+
112+ def okcmd (self):
113+ self.quitcmd()
114+
115+ def quitcmd (self):
116+ self.exit = 0
117+
118+ def mainloop(self):
119+ while self.exit < 0:
120+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
121+
122+ def destroy (self):
123+ self.root.destroy()
124+
125+
126+# This "if" statement makes it possible to run this script file inside or
127+# outside of the main demo program "tixwidgets.py".
128+#
129+if __name__== '__main__' :
130+ root=Tix.Tk()
131+ RunSample(root)
sys/src/cmd/python/Demo/tix/samples/SHList2.py+168−0
@@ -0,0 +1,168 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: SHList2.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidget": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program using tixwish.
12+
13+# This file demonstrates how to use multiple columns and multiple styles
14+# in the tixHList widget
15+#
16+# In a tixHList widget, you can have one ore more columns.
17+#
18+
19+import Tix
20+
21+TCL_ALL_EVENTS = 0
22+
23+def RunSample (root):
24+ shlist = DemoSHList(root)
25+ shlist.mainloop()
26+ shlist.destroy()
27+
28+class DemoSHList:
29+ def __init__(self, w):
30+ self.root = w
31+ self.exit = -1
32+
33+ z = w.winfo_toplevel()
34+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
35+
36+ # We create the frame and the ScrolledHList widget
37+ # at the top of the dialog box
38+ #
39+ top = Tix.Frame( w, relief=Tix.RAISED, bd=1)
40+
41+ # Put a simple hierachy into the HList (two levels). Use colors and
42+ # separator widgets (frames) to make the list look fancy
43+ #
44+ top.a = Tix.ScrolledHList(top, options='hlist.columns 3 hlist.header 1' )
45+ top.a.pack( expand=1, fill=Tix.BOTH, padx=10, pady=10, side=Tix.TOP)
46+
47+ hlist=top.a.hlist
48+
49+ # Create the title for the HList widget
50+ # >> Notice that we have set the hlist.header subwidget option to true
51+ # so that the header is displayed
52+ #
53+
54+ boldfont=hlist.tk.call('tix','option','get','bold_font')
55+
56+ # First some styles for the headers
57+ style={}
58+ style['header'] = Tix.DisplayStyle(Tix.TEXT, refwindow=hlist,
59+ anchor=Tix.CENTER, padx=8, pady=2, font = boldfont )
60+
61+ hlist.header_create(0, itemtype=Tix.TEXT, text='Name',
62+ style=style['header'])
63+ hlist.header_create(1, itemtype=Tix.TEXT, text='Position',
64+ style=style['header'])
65+
66+ # Notice that we use 3 columns in the hlist widget. This way when the user
67+ # expands the windows wide, the right side of the header doesn't look
68+ # chopped off. The following line ensures that the 3 column header is
69+ # not shown unless the hlist window is wider than its contents.
70+ #
71+ hlist.column_width(2,0)
72+
73+ # This is our little relational database
74+ #
75+ boss = ('doe', 'John Doe', 'Director')
76+
77+ managers = [
78+ ('jeff', 'Jeff Waxman', 'Manager'),
79+ ('john', 'John Lee', 'Manager'),
80+ ('peter', 'Peter Kenson', 'Manager')
81+ ]
82+
83+ employees = [
84+ ('alex', 'john', 'Alex Kellman', 'Clerk'),
85+ ('alan', 'john', 'Alan Adams', 'Clerk'),
86+ ('andy', 'peter', 'Andreas Crawford', 'Salesman'),
87+ ('doug', 'jeff', 'Douglas Bloom', 'Clerk'),
88+ ('jon', 'peter', 'Jon Baraki', 'Salesman'),
89+ ('chris', 'jeff', 'Chris Geoffrey', 'Clerk'),
90+ ('chuck', 'jeff', 'Chuck McLean', 'Cleaner')
91+ ]
92+
93+ style['mgr_name'] = Tix.DisplayStyle(Tix.TEXT, refwindow=hlist)
94+
95+ style['mgr_posn'] = Tix.DisplayStyle(Tix.TEXT, padx=8, refwindow=hlist)
96+
97+ style['empl_name'] = Tix.DisplayStyle(Tix.TEXT, refwindow=hlist)
98+
99+ style['empl_posn'] = Tix.DisplayStyle(Tix.TEXT, padx=8, refwindow=hlist)
100+
101+ # Let configure the appearance of the HList subwidget
102+ #
103+ hlist.config(separator='.', width=25, drawbranch=0, indent=10)
104+ hlist.column_width(0, chars=20)
105+
106+ # Create the boss
107+ #
108+ hlist.add ('.', itemtype=Tix.TEXT, text=boss[1],
109+ style=style['mgr_name'])
110+ hlist.item_create('.', 1, itemtype=Tix.TEXT, text=boss[2],
111+ style=style['mgr_posn'])
112+
113+ # Create the managers
114+ #
115+
116+ for key,name,posn in managers :
117+ e= '.'+ key
118+ hlist.add(e, itemtype=Tix.TEXT, text=name,
119+ style=style['mgr_name'])
120+ hlist.item_create(e, 1, itemtype=Tix.TEXT, text=posn,
121+ style=style['mgr_posn'])
122+
123+
124+ for key,mgr,name,posn in employees :
125+ # "." is the separator character we chose above
126+
127+ entrypath = '.' + mgr + '.' + key
128+
129+ # ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
130+ # parent entryPath / child's name
131+
132+ hlist.add(entrypath, text=name, style=style['empl_name'])
133+ hlist.item_create(entrypath, 1, itemtype=Tix.TEXT,
134+ text = posn, style = style['empl_posn'] )
135+
136+
137+ # Use a ButtonBox to hold the buttons.
138+ #
139+ box= Tix.ButtonBox(top, orientation=Tix.HORIZONTAL )
140+ box.add( 'ok', text='Ok', underline=0, width=6,
141+ command = self.okcmd )
142+
143+ box.add( 'cancel', text='Cancel', underline=0, width=6,
144+ command = self.quitcmd )
145+
146+ box.pack( side=Tix.BOTTOM, fill=Tix.X)
147+ top.pack( side=Tix.TOP, fill=Tix.BOTH, expand=1 )
148+
149+ def okcmd (self):
150+ self.quitcmd()
151+
152+ def quitcmd (self):
153+ self.exit = 0
154+
155+ def mainloop(self):
156+ while self.exit < 0:
157+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
158+
159+ def destroy (self):
160+ self.root.destroy()
161+
162+
163+# This "if" statement makes it possible to run this script file inside or
164+# outside of the main demo program "tixwidgets.py".
165+#
166+if __name__== '__main__' :
167+ root=Tix.Tk()
168+ RunSample(root)
sys/src/cmd/python/Demo/tix/samples/Tree.py+80−0
@@ -0,0 +1,80 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: Tree.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# Tix Demostration Program
6+#
7+# This sample program is structured in such a way so that it can be
8+# executed from the Tix demo program "tixwidgets.py": it must have a
9+# procedure called "RunSample". It should also have the "if" statment
10+# at the end of this file so that it can be run as a standalone
11+# program.
12+
13+# This file demonstrates how to use the TixTree widget to display
14+# dynamic hierachical data (the files in the Unix file system)
15+#
16+
17+import Tix, os
18+
19+def RunSample(w):
20+ top = Tix.Frame(w, relief=Tix.RAISED, bd=1)
21+ tree = Tix.Tree(top, options='separator "/"')
22+ tree.pack(expand=1, fill=Tix.BOTH, padx=10, pady=10, side=Tix.LEFT)
23+ tree['opencmd'] = lambda dir=None, w=tree: opendir(w, dir)
24+
25+ # The / directory is added in the "open" mode. The user can open it
26+ # and then browse its subdirectories ...
27+ adddir(tree, "/")
28+
29+ box = Tix.ButtonBox(w, orientation=Tix.HORIZONTAL)
30+ box.add('ok', text='Ok', underline=0, command=w.destroy, width=6)
31+ box.add('cancel', text='Cancel', underline=0, command=w.destroy, width=6)
32+ box.pack(side=Tix.BOTTOM, fill=Tix.X)
33+ top.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
34+
35+def adddir(tree, dir):
36+ if dir == '/':
37+ text = '/'
38+ else:
39+ text = os.path.basename(dir)
40+ tree.hlist.add(dir, itemtype=Tix.IMAGETEXT, text=text,
41+ image=tree.tk.call('tix', 'getimage', 'folder'))
42+ try:
43+ os.listdir(dir)
44+ tree.setmode(dir, 'open')
45+ except os.error:
46+ # No read permission ?
47+ pass
48+
49+# This function is called whenever the user presses the (+) indicator or
50+# double clicks on a directory whose mode is "open". It loads the files
51+# inside that directory into the Tree widget.
52+#
53+# Note we didn't specify the closecmd option for the Tree widget, so it
54+# performs the default action when the user presses the (-) indicator or
55+# double clicks on a directory whose mode is "close": hide all of its child
56+# entries
57+def opendir(tree, dir):
58+ entries = tree.hlist.info_children(dir)
59+ if entries:
60+ # We have already loaded this directory. Let's just
61+ # show all the child entries
62+ #
63+ # Note: since we load the directory only once, it will not be
64+ # refreshed if the you add or remove files from this
65+ # directory.
66+ #
67+ for entry in entries:
68+ tree.hlist.show_entry(entry)
69+ files = os.listdir(dir)
70+ for file in files:
71+ if os.path.isdir(dir + '/' + file):
72+ adddir(tree, dir + '/' + file)
73+ else:
74+ tree.hlist.add(dir + '/' + file, itemtype=Tix.IMAGETEXT, text=file,
75+ image=tree.tk.call('tix', 'getimage', 'file'))
76+
77+if __name__ == '__main__':
78+ root = Tix.Tk()
79+ RunSample(root)
80+ root.mainloop()
sys/src/cmd/python/Demo/tix/tixwidgets.py+1003−0
@@ -0,0 +1,1003 @@
1+# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
2+#
3+# $Id: tixwidgets.py 36560 2004-07-18 06:16:08Z tim_one $
4+#
5+# tixwidgets.py --
6+#
7+# For Tix, see http://tix.sourceforge.net
8+#
9+# This is a demo program of some of the Tix widgets available in Python.
10+# If you have installed Python & Tix properly, you can execute this as
11+#
12+# % python tixwidgets.py
13+#
14+
15+import os, os.path, sys, Tix
16+from Tkconstants import *
17+import traceback, tkMessageBox
18+
19+TCL_DONT_WAIT = 1<<1
20+TCL_WINDOW_EVENTS = 1<<2
21+TCL_FILE_EVENTS = 1<<3
22+TCL_TIMER_EVENTS = 1<<4
23+TCL_IDLE_EVENTS = 1<<5
24+TCL_ALL_EVENTS = 0
25+
26+class Demo:
27+ def __init__(self, top):
28+ self.root = top
29+ self.exit = -1
30+
31+ self.dir = None # script directory
32+ self.balloon = None # balloon widget
33+ self.useBalloons = Tix.StringVar()
34+ self.useBalloons.set('0')
35+ self.statusbar = None # status bar widget
36+ self.welmsg = None # Msg widget
37+ self.welfont = '' # font name
38+ self.welsize = '' # font size
39+
40+ progname = sys.argv[0]
41+ dirname = os.path.dirname(progname)
42+ if dirname and dirname != os.curdir:
43+ self.dir = dirname
44+ index = -1
45+ for i in range(len(sys.path)):
46+ p = sys.path[i]
47+ if p in ("", os.curdir):
48+ index = i
49+ if index >= 0:
50+ sys.path[index] = dirname
51+ else:
52+ sys.path.insert(0, dirname)
53+ else:
54+ self.dir = os.getcwd()
55+ sys.path.insert(0, self.dir+'/samples')
56+
57+ def MkMainMenu(self):
58+ top = self.root
59+ w = Tix.Frame(top, bd=2, relief=RAISED)
60+ file = Tix.Menubutton(w, text='File', underline=0, takefocus=0)
61+ help = Tix.Menubutton(w, text='Help', underline=0, takefocus=0)
62+ file.pack(side=LEFT)
63+ help.pack(side=RIGHT)
64+ fm = Tix.Menu(file, tearoff=0)
65+ file['menu'] = fm
66+ hm = Tix.Menu(help, tearoff=0)
67+ help['menu'] = hm
68+
69+ fm.add_command(label='Exit', underline=1,
70+ command = lambda self=self: self.quitcmd () )
71+ hm.add_checkbutton(label='BalloonHelp', underline=0, command=ToggleHelp,
72+ variable=self.useBalloons)
73+ # The trace variable option doesn't seem to work, instead I use 'command'
74+ #apply(w.tk.call, ('trace', 'variable', self.useBalloons, 'w',
75+ # ToggleHelp))
76+
77+ return w
78+
79+ def MkMainNotebook(self):
80+ top = self.root
81+ w = Tix.NoteBook(top, ipadx=5, ipady=5, options="""
82+ tagPadX 6
83+ tagPadY 4
84+ borderWidth 2
85+ """)
86+ # This may be required if there is no *Background option
87+ top['bg'] = w['bg']
88+
89+ w.add('wel', label='Welcome', underline=0,
90+ createcmd=lambda w=w, name='wel': MkWelcome(w, name))
91+ w.add('cho', label='Choosers', underline=0,
92+ createcmd=lambda w=w, name='cho': MkChoosers(w, name))
93+ w.add('scr', label='Scrolled Widgets', underline=0,
94+ createcmd=lambda w=w, name='scr': MkScroll(w, name))
95+ w.add('mgr', label='Manager Widgets', underline=0,
96+ createcmd=lambda w=w, name='mgr': MkManager(w, name))
97+ w.add('dir', label='Directory List', underline=0,
98+ createcmd=lambda w=w, name='dir': MkDirList(w, name))
99+ w.add('exp', label='Run Sample Programs', underline=0,
100+ createcmd=lambda w=w, name='exp': MkSample(w, name))
101+ return w
102+
103+ def MkMainStatus(self):
104+ global demo
105+ top = self.root
106+
107+ w = Tix.Frame(top, relief=Tix.RAISED, bd=1)
108+ demo.statusbar = Tix.Label(w, relief=Tix.SUNKEN, bd=1)
109+ demo.statusbar.form(padx=3, pady=3, left=0, right='%70')
110+ return w
111+
112+ def build(self):
113+ root = self.root
114+ z = root.winfo_toplevel()
115+ z.wm_title('Tix Widget Demonstration')
116+ if z.winfo_screenwidth() <= 800:
117+ z.geometry('790x590+10+10')
118+ else:
119+ z.geometry('890x640+10+10')
120+ demo.balloon = Tix.Balloon(root)
121+ frame1 = self.MkMainMenu()
122+ frame2 = self.MkMainNotebook()
123+ frame3 = self.MkMainStatus()
124+ frame1.pack(side=TOP, fill=X)
125+ frame3.pack(side=BOTTOM, fill=X)
126+ frame2.pack(side=TOP, expand=1, fill=BOTH, padx=4, pady=4)
127+ demo.balloon['statusbar'] = demo.statusbar
128+ z.wm_protocol("WM_DELETE_WINDOW", lambda self=self: self.quitcmd())
129+
130+ # To show Tcl errors - uncomment this to see the listbox bug.
131+ # Tkinter defines a Tcl tkerror procedure that in effect
132+ # silences all background Tcl error reporting.
133+ # root.tk.eval('if {[info commands tkerror] != ""} {rename tkerror pytkerror}')
134+ def quitcmd (self):
135+ """Quit our mainloop. It is up to you to call root.destroy() after."""
136+ self.exit = 0
137+
138+ def loop(self):
139+ """This is an explict replacement for _tkinter mainloop()
140+ It lets you catch keyboard interrupts easier, and avoids
141+ the 20 msec. dead sleep() which burns a constant CPU."""
142+ while self.exit < 0:
143+ # There are 2 whiles here. The outer one lets you continue
144+ # after a ^C interrupt.
145+ try:
146+ # This is the replacement for _tkinter mainloop()
147+ # It blocks waiting for the next Tcl event using select.
148+ while self.exit < 0:
149+ self.root.tk.dooneevent(TCL_ALL_EVENTS)
150+ except SystemExit:
151+ # Tkinter uses SystemExit to exit
152+ #print 'Exit'
153+ self.exit = 1
154+ return
155+ except KeyboardInterrupt:
156+ if tkMessageBox.askquestion ('Interrupt', 'Really Quit?') == 'yes':
157+ # self.tk.eval('exit')
158+ self.exit = 1
159+ return
160+ continue
161+ except:
162+ # Otherwise it's some other error - be nice and say why
163+ t, v, tb = sys.exc_info()
164+ text = ""
165+ for line in traceback.format_exception(t,v,tb):
166+ text += line + '\n'
167+ try: tkMessageBox.showerror ('Error', text)
168+ except: pass
169+ self.exit = 1
170+ raise SystemExit, 1
171+
172+ def destroy (self):
173+ self.root.destroy()
174+
175+def RunMain(root):
176+ global demo
177+
178+ demo = Demo(root)
179+
180+ demo.build()
181+ demo.loop()
182+ demo.destroy()
183+
184+# Tabs
185+def MkWelcome(nb, name):
186+ w = nb.page(name)
187+ bar = MkWelcomeBar(w)
188+ text = MkWelcomeText(w)
189+ bar.pack(side=TOP, fill=X, padx=2, pady=2)
190+ text.pack(side=TOP, fill=BOTH, expand=1)
191+
192+def MkWelcomeBar(top):
193+ global demo
194+
195+ w = Tix.Frame(top, bd=2, relief=Tix.GROOVE)
196+ b1 = Tix.ComboBox(w, command=lambda w=top: MainTextFont(w))
197+ b2 = Tix.ComboBox(w, command=lambda w=top: MainTextFont(w))
198+ b1.entry['width'] = 15
199+ b1.slistbox.listbox['height'] = 3
200+ b2.entry['width'] = 4
201+ b2.slistbox.listbox['height'] = 3
202+
203+ demo.welfont = b1
204+ demo.welsize = b2
205+
206+ b1.insert(Tix.END, 'Courier')
207+ b1.insert(Tix.END, 'Helvetica')
208+ b1.insert(Tix.END, 'Lucida')
209+ b1.insert(Tix.END, 'Times Roman')
210+
211+ b2.insert(Tix.END, '8')
212+ b2.insert(Tix.END, '10')
213+ b2.insert(Tix.END, '12')
214+ b2.insert(Tix.END, '14')
215+ b2.insert(Tix.END, '18')
216+
217+ b1.pick(1)
218+ b2.pick(3)
219+
220+ b1.pack(side=Tix.LEFT, padx=4, pady=4)
221+ b2.pack(side=Tix.LEFT, padx=4, pady=4)
222+
223+ demo.balloon.bind_widget(b1, msg='Choose\na font',
224+ statusmsg='Choose a font for this page')
225+ demo.balloon.bind_widget(b2, msg='Point size',
226+ statusmsg='Choose the font size for this page')
227+ return w
228+
229+def MkWelcomeText(top):
230+ global demo
231+
232+ w = Tix.ScrolledWindow(top, scrollbar='auto')
233+ win = w.window
234+ text = 'Welcome to TIX in Python'
235+ title = Tix.Label(win,
236+ bd=0, width=30, anchor=Tix.N, text=text)
237+ msg = Tix.Message(win,
238+ bd=0, width=400, anchor=Tix.N,
239+ text='Tix is a set of mega-widgets based on TK. This program \
240+demonstrates the widgets in the Tix widget set. You can choose the pages \
241+in this window to look at the corresponding widgets. \n\n\
242+To quit this program, choose the "File | Exit" command.\n\n\
243+For more information, see http://tix.sourceforge.net.')
244+ title.pack(expand=1, fill=Tix.BOTH, padx=10, pady=10)
245+ msg.pack(expand=1, fill=Tix.BOTH, padx=10, pady=10)
246+ demo.welmsg = msg
247+ return w
248+
249+def MainTextFont(w):
250+ global demo
251+
252+ if not demo.welmsg:
253+ return
254+ font = demo.welfont['value']
255+ point = demo.welsize['value']
256+ if font == 'Times Roman':
257+ font = 'times'
258+ fontstr = '%s %s' % (font, point)
259+ demo.welmsg['font'] = fontstr
260+
261+def ToggleHelp():
262+ if demo.useBalloons.get() == '1':
263+ demo.balloon['state'] = 'both'
264+ else:
265+ demo.balloon['state'] = 'none'
266+
267+def MkChoosers(nb, name):
268+ w = nb.page(name)
269+ options = "label.padX 4"
270+
271+ til = Tix.LabelFrame(w, label='Chooser Widgets', options=options)
272+ cbx = Tix.LabelFrame(w, label='tixComboBox', options=options)
273+ ctl = Tix.LabelFrame(w, label='tixControl', options=options)
274+ sel = Tix.LabelFrame(w, label='tixSelect', options=options)
275+ opt = Tix.LabelFrame(w, label='tixOptionMenu', options=options)
276+ fil = Tix.LabelFrame(w, label='tixFileEntry', options=options)
277+ fbx = Tix.LabelFrame(w, label='tixFileSelectBox', options=options)
278+ tbr = Tix.LabelFrame(w, label='Tool Bar', options=options)
279+
280+ MkTitle(til.frame)
281+ MkCombo(cbx.frame)
282+ MkControl(ctl.frame)
283+ MkSelect(sel.frame)
284+ MkOptMenu(opt.frame)
285+ MkFileEnt(fil.frame)
286+ MkFileBox(fbx.frame)
287+ MkToolBar(tbr.frame)
288+
289+ # First column: comBox and selector
290+ cbx.form(top=0, left=0, right='%33')
291+ sel.form(left=0, right='&'+str(cbx), top=cbx)
292+ opt.form(left=0, right='&'+str(cbx), top=sel, bottom=-1)
293+
294+ # Second column: title .. etc
295+ til.form(left=cbx, top=0,right='%66')
296+ ctl.form(left=cbx, right='&'+str(til), top=til)
297+ fil.form(left=cbx, right='&'+str(til), top=ctl)
298+ tbr.form(left=cbx, right='&'+str(til), top=fil, bottom=-1)
299+
300+ #
301+ # Third column: file selection
302+ fbx.form(right=-1, top=0, left='%66')
303+
304+def MkCombo(w):
305+ options="label.width %d label.anchor %s entry.width %d" % (10, Tix.E, 14)
306+
307+ static = Tix.ComboBox(w, label='Static', editable=0, options=options)
308+ editable = Tix.ComboBox(w, label='Editable', editable=1, options=options)
309+ history = Tix.ComboBox(w, label='History', editable=1, history=1,
310+ anchor=Tix.E, options=options)
311+ static.insert(Tix.END, 'January')
312+ static.insert(Tix.END, 'February')
313+ static.insert(Tix.END, 'March')
314+ static.insert(Tix.END, 'April')
315+ static.insert(Tix.END, 'May')
316+ static.insert(Tix.END, 'June')
317+ static.insert(Tix.END, 'July')
318+ static.insert(Tix.END, 'August')
319+ static.insert(Tix.END, 'September')
320+ static.insert(Tix.END, 'October')
321+ static.insert(Tix.END, 'November')
322+ static.insert(Tix.END, 'December')
323+
324+ editable.insert(Tix.END, 'Angola')
325+ editable.insert(Tix.END, 'Bangladesh')
326+ editable.insert(Tix.END, 'China')
327+ editable.insert(Tix.END, 'Denmark')
328+ editable.insert(Tix.END, 'Ecuador')
329+
330+ history.insert(Tix.END, '/usr/bin/ksh')
331+ history.insert(Tix.END, '/usr/local/lib/python')
332+ history.insert(Tix.END, '/var/adm')
333+
334+ static.pack(side=Tix.TOP, padx=5, pady=3)
335+ editable.pack(side=Tix.TOP, padx=5, pady=3)
336+ history.pack(side=Tix.TOP, padx=5, pady=3)
337+
338+states = ['Bengal', 'Delhi', 'Karnataka', 'Tamil Nadu']
339+
340+def spin_cmd(w, inc):
341+ idx = states.index(demo_spintxt.get()) + inc
342+ if idx < 0:
343+ idx = len(states) - 1
344+ elif idx >= len(states):
345+ idx = 0
346+# following doesn't work.
347+# return states[idx]
348+ demo_spintxt.set(states[idx]) # this works
349+
350+def spin_validate(w):
351+ global states, demo_spintxt
352+
353+ try:
354+ i = states.index(demo_spintxt.get())
355+ except ValueError:
356+ return states[0]
357+ return states[i]
358+ # why this procedure works as opposed to the previous one beats me.
359+
360+def MkControl(w):
361+ global demo_spintxt
362+
363+ options="label.width %d label.anchor %s entry.width %d" % (10, Tix.E, 13)
364+
365+ demo_spintxt = Tix.StringVar()
366+ demo_spintxt.set(states[0])
367+ simple = Tix.Control(w, label='Numbers', options=options)
368+ spintxt = Tix.Control(w, label='States', variable=demo_spintxt,
369+ options=options)
370+ spintxt['incrcmd'] = lambda w=spintxt: spin_cmd(w, 1)
371+ spintxt['decrcmd'] = lambda w=spintxt: spin_cmd(w, -1)
372+ spintxt['validatecmd'] = lambda w=spintxt: spin_validate(w)
373+
374+ simple.pack(side=Tix.TOP, padx=5, pady=3)
375+ spintxt.pack(side=Tix.TOP, padx=5, pady=3)
376+
377+def MkSelect(w):
378+ options = "label.anchor %s" % Tix.CENTER
379+
380+ sel1 = Tix.Select(w, label='Mere Mortals', allowzero=1, radio=1,
381+ orientation=Tix.VERTICAL,
382+ labelside=Tix.TOP,
383+ options=options)
384+ sel2 = Tix.Select(w, label='Geeks', allowzero=1, radio=0,
385+ orientation=Tix.VERTICAL,
386+ labelside= Tix.TOP,
387+ options=options)
388+
389+ sel1.add('eat', text='Eat')
390+ sel1.add('work', text='Work')
391+ sel1.add('play', text='Play')
392+ sel1.add('party', text='Party')
393+ sel1.add('sleep', text='Sleep')
394+
395+ sel2.add('eat', text='Eat')
396+ sel2.add('prog1', text='Program')
397+ sel2.add('prog2', text='Program')
398+ sel2.add('prog3', text='Program')
399+ sel2.add('sleep', text='Sleep')
400+
401+ sel1.pack(side=Tix.LEFT, padx=5, pady=3, fill=Tix.X)
402+ sel2.pack(side=Tix.LEFT, padx=5, pady=3, fill=Tix.X)
403+
404+def MkOptMenu(w):
405+ options='menubutton.width 15 label.anchor %s' % Tix.E
406+
407+ m = Tix.OptionMenu(w, label='File Format : ', options=options)
408+ m.add_command('text', label='Plain Text')
409+ m.add_command('post', label='PostScript')
410+ m.add_command('format', label='Formatted Text')
411+ m.add_command('html', label='HTML')
412+ m.add_command('sep')
413+ m.add_command('tex', label='LaTeX')
414+ m.add_command('rtf', label='Rich Text Format')
415+
416+ m.pack(fill=Tix.X, padx=5, pady=3)
417+
418+def MkFileEnt(w):
419+ msg = Tix.Message(w,
420+ relief=Tix.FLAT, width=240, anchor=Tix.N,
421+ text='Press the "open file" icon button and a TixFileSelectDialog will popup.')
422+ ent = Tix.FileEntry(w, label='Select a file : ')
423+ msg.pack(side=Tix.TOP, expand=1, fill=Tix.BOTH, padx=3, pady=3)
424+ ent.pack(side=Tix.TOP, fill=Tix.X, padx=3, pady=3)
425+
426+def MkFileBox(w):
427+ """The FileSelectBox is a Motif-style box with various enhancements.
428+ For example, you can adjust the size of the two listboxes
429+ and your past selections are recorded.
430+ """
431+ msg = Tix.Message(w,
432+ relief=Tix.FLAT, width=240, anchor=Tix.N,
433+ text='The Tix FileSelectBox is a Motif-style box with various enhancements. For example, you can adjust the size of the two listboxes and your past selections are recorded.')
434+ box = Tix.FileSelectBox(w)
435+ msg.pack(side=Tix.TOP, expand=1, fill=Tix.BOTH, padx=3, pady=3)
436+ box.pack(side=Tix.TOP, fill=Tix.X, padx=3, pady=3)
437+
438+def MkToolBar(w):
439+ """The Select widget is also good for arranging buttons in a tool bar.
440+ """
441+ global demo
442+
443+ options='frame.borderWidth 1'

560 more lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/README+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/AttrDialog.py+452−0

This diff is large: its 453 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/ManPage.py+220−0

This diff is large: its 221 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/MimeViewer.py+143−0

This diff is large: its 144 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/ShellWindow.py+151−0

This diff is large: its 152 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/brownian.py+50−0

This diff is large: its 51 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/canvasevents.py+244−0

This diff is large: its 245 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/dialog.py+109−0

This diff is large: its 110 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/electrons.py+91−0

This diff is large: its 92 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/hanoi.py+154−0

This diff is large: its 155 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/hello.py+17−0

This diff is large: its 18 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/imagedraw.py+23−0

This diff is large: its 24 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/imageview.py+12−0

This diff is large: its 13 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/kill.py+98−0

This diff is large: its 99 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/listtree.py+37−0

This diff is large: its 38 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/mbox.py+285−0

This diff is large: its 286 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/newmenubardemo.py+47−0

This diff is large: its 48 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/optionmenu.py+27−0

This diff is large: its 28 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/paint.py+60−0

This diff is large: its 61 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/rmt.py+159−0

This diff is large: its 160 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/solitaire.py+637−0

This diff is large: its 638 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/sortvisu.py+634−0

This diff is large: its 635 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/ss1.py+845−0

This diff is large: its 846 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/svkill.py+128−0

This diff is large: its 129 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/switch.py+55−0

This diff is large: its 56 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/tkman.py+267−0

This diff is large: its 268 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/guido/wish.py+27−0

This diff is large: its 28 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/00-HELLO-WORLD.py+27−0

This diff is large: its 28 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/README+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/animation-simple.py+35−0

This diff is large: its 36 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/animation-w-velocity-ctrl.py+44−0

This diff is large: its 45 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/bind-w-mult-calls-p-type.py+44−0

This diff is large: its 45 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-demo-simple.py+28−0

This diff is large: its 29 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-gridding.py+61−0

This diff is large: its 62 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-moving-or-creating.py+62−0

This diff is large: its 63 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-moving-w-mouse.py+55−0

This diff is large: its 56 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-mult-item-sel.py+78−0

This diff is large: its 79 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-reading-tag-info.py+49−0

This diff is large: its 50 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-w-widget-draw-el.py+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/canvas-with-scrollbars.py+60−0

This diff is large: its 61 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/dialog-box.py+64−0

This diff is large: its 65 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/entry-simple.py+24−0

This diff is large: its 25 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/entry-with-shared-variable.py+46−0

This diff is large: its 47 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/killing-window-w-wm.py+42−0

This diff is large: its 43 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/menu-all-types-of-entries.py+244−0

This diff is large: its 245 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/menu-simple.py+112−0

This diff is large: its 113 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/not-what-you-might-think-1.py+28−0

This diff is large: its 29 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/not-what-you-might-think-2.py+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/packer-and-placer-together.py+41−0

This diff is large: its 42 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/packer-simple.py+32−0

This diff is large: its 33 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/placer-simple.py+39−0

This diff is large: its 40 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/pong-demo-1.py+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/printing-coords-of-items.py+61−0

This diff is large: its 62 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/radiobutton-simple.py+62−0

This diff is large: its 63 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/rubber-band-box-demo-1.py+58−0

This diff is large: its 59 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/rubber-line-demo-1.py+51−0

This diff is large: its 52 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/slider-demo-1.py+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/subclass-existing-widgets.py+28−0

This diff is large: its 29 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/two-radio-groups.py+110−0

This diff is large: its 111 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/window-creation-more.py+35−0

This diff is large: its 36 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/window-creation-simple.py+31−0

This diff is large: its 32 lines aren’t shown here.

sys/src/cmd/python/Demo/tkinter/matt/window-creation-w-location.py+45−0

This diff is large: its 46 lines aren’t shown here.

sys/src/cmd/python/Demo/xml/elem_count.py+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Demo/xml/roundtrip.py+45−0

This diff is large: its 46 lines aren’t shown here.

sys/src/cmd/python/Demo/xml/rss2html.py+91−0

This diff is large: its 92 lines aren’t shown here.

sys/src/cmd/python/Demo/zlib/minigzip.py+133−0

This diff is large: its 134 lines aren’t shown here.

sys/src/cmd/python/Demo/zlib/zlibdemo.py+48−0

This diff is large: its 49 lines aren’t shown here.

sys/src/cmd/python/Demo/zlib/zlibdemo.py.gz+0−0

Binary file not shown.

sys/src/cmd/python/Doc/ACKS+202−0

This diff is large: its 203 lines aren’t shown here.

sys/src/cmd/python/Doc/Makefile+736−0

This diff is large: its 737 lines aren’t shown here.

sys/src/cmd/python/Doc/Makefile.deps+386−0

This diff is large: its 387 lines aren’t shown here.

sys/src/cmd/python/Doc/README+246−0

This diff is large: its 247 lines aren’t shown here.

sys/src/cmd/python/Doc/TODO+74−0

This diff is large: its 75 lines aren’t shown here.

sys/src/cmd/python/Doc/api/abstract.tex+1057−0

This diff is large: its 1058 lines aren’t shown here.

sys/src/cmd/python/Doc/api/api.tex+60−0

This diff is large: its 61 lines aren’t shown here.

sys/src/cmd/python/Doc/api/concrete.tex+3203−0

This diff is large: its 3204 lines aren’t shown here.

sys/src/cmd/python/Doc/api/exceptions.tex+442−0

This diff is large: its 443 lines aren’t shown here.

sys/src/cmd/python/Doc/api/init.tex+884−0

This diff is large: its 885 lines aren’t shown here.

sys/src/cmd/python/Doc/api/intro.tex+627−0

This diff is large: its 628 lines aren’t shown here.

sys/src/cmd/python/Doc/api/memory.tex+204−0

This diff is large: its 205 lines aren’t shown here.

sys/src/cmd/python/Doc/api/newtypes.tex+1780−0

This diff is large: its 1781 lines aren’t shown here.

sys/src/cmd/python/Doc/api/refcounting.tex+69−0

This diff is large: its 70 lines aren’t shown here.

sys/src/cmd/python/Doc/api/refcounts.dat+1756−0

This diff is large: its 1757 lines aren’t shown here.

sys/src/cmd/python/Doc/api/utilities.tex+1023−0

This diff is large: its 1024 lines aren’t shown here.

sys/src/cmd/python/Doc/api/veryhigh.tex+287−0

This diff is large: its 288 lines aren’t shown here.

sys/src/cmd/python/Doc/commontex/boilerplate.tex+9−0

This diff is large: its 10 lines aren’t shown here.

sys/src/cmd/python/Doc/commontex/copyright.tex+14−0

This diff is large: its 15 lines aren’t shown here.

sys/src/cmd/python/Doc/commontex/license.tex+673−0

This diff is large: its 674 lines aren’t shown here.

sys/src/cmd/python/Doc/commontex/reportingbugs.tex+61−0

This diff is large: its 62 lines aren’t shown here.

sys/src/cmd/python/Doc/commontex/typestruct.h+76−0

This diff is large: its 77 lines aren’t shown here.

sys/src/cmd/python/Doc/dist/dist.tex+3795−0

This diff is large: its 3796 lines aren’t shown here.

sys/src/cmd/python/Doc/dist/sysconfig.tex+113−0

This diff is large: its 114 lines aren’t shown here.

sys/src/cmd/python/Doc/doc/doc.tex+2129−0

This diff is large: its 2130 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/building.tex+143−0

This diff is large: its 144 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/embedding.tex+316−0

This diff is large: its 317 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/ext.tex+67−0

This diff is large: its 68 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/extending.tex+1390−0

This diff is large: its 1391 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/newtypes.tex+1765−0

This diff is large: its 1766 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/noddy.c+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/noddy2.c+190−0

This diff is large: its 191 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/noddy3.c+243−0

This diff is large: its 244 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/noddy4.c+224−0

This diff is large: its 225 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/run-func.c+68−0

This diff is large: its 69 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/setup.py+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/shoddy.c+91−0

This diff is large: its 92 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/test.py+213−0

This diff is large: its 214 lines aren’t shown here.

sys/src/cmd/python/Doc/ext/windows.tex+320−0

This diff is large: its 321 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/Makefile+84−0

This diff is large: its 85 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/TODO+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/advocacy.tex+411−0

This diff is large: its 412 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/curses.tex+485−0

This diff is large: its 486 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/doanddont.tex+344−0

This diff is large: its 345 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/regex.tex+1463−0

This diff is large: its 1464 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/sockets.tex+465−0

This diff is large: its 466 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/unicode.rst+766−0

This diff is large: its 767 lines aren’t shown here.

sys/src/cmd/python/Doc/howto/urllib2.rst+598−0

This diff is large: its 599 lines aren’t shown here.

sys/src/cmd/python/Doc/html/about.dat+24−0

This diff is large: its 25 lines aren’t shown here.

sys/src/cmd/python/Doc/html/about.html+84−0

This diff is large: its 85 lines aren’t shown here.

sys/src/cmd/python/Doc/html/icons/blank.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/blank.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/contents.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/contents.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/index.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/index.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/modules.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/modules.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/next.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/next.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/previous.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/previous.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/pyfav.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/pyfav.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/up.gif+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/icons/up.png+0−0

Binary file not shown.

sys/src/cmd/python/Doc/html/index.html.in+140−0

This diff is large: its 141 lines aren’t shown here.

sys/src/cmd/python/Doc/html/stdabout.dat+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/html/style.css+243−0

This diff is large: its 244 lines aren’t shown here.

sys/src/cmd/python/Doc/info/Makefile+82−0

This diff is large: its 83 lines aren’t shown here.

sys/src/cmd/python/Doc/info/README+21−0

This diff is large: its 22 lines aren’t shown here.

sys/src/cmd/python/Doc/info/python.dir+11−0

This diff is large: its 12 lines aren’t shown here.

sys/src/cmd/python/Doc/inst/inst.tex+1112−0

This diff is large: its 1113 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/archiving.tex+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/asttable.tex+283−0

This diff is large: its 284 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/caseless.py+60−0

This diff is large: its 61 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/compiler.tex+354−0

This diff is large: its 355 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/custominterp.tex+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/datatypes.tex+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/development.tex+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/distutils.tex+38−0

This diff is large: its 39 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/email-dir.py+115−0

This diff is large: its 116 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/email-mime.py+32−0

This diff is large: its 33 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/email-simple.py+25−0

This diff is large: its 26 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/email-unpack.py+68−0

This diff is large: its 69 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/email.tex+402−0

This diff is large: its 403 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailcharsets.tex+244−0

This diff is large: its 245 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailencoders.tex+47−0

This diff is large: its 48 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailexc.tex+87−0

This diff is large: its 88 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailgenerator.tex+133−0

This diff is large: its 134 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailheaders.tex+178−0

This diff is large: its 179 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailiter.tex+65−0

This diff is large: its 66 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailmessage.tex+561−0

This diff is large: its 562 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailmimebase.tex+186−0

This diff is large: its 187 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailparser.tex+208−0

This diff is large: its 209 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/emailutil.tex+157−0

This diff is large: its 158 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/fileformats.tex+7−0

This diff is large: its 8 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/filesys.tex+18−0

This diff is large: its 19 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/frameworks.tex+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/i18n.tex+11−0

This diff is large: its 12 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/internet.tex+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/ipc.tex+14−0

This diff is large: its 15 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/language.tex+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/lib.tex+487−0

This diff is large: its 488 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libaifc.tex+202−0

This diff is large: its 203 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libal.tex+181−0

This diff is large: its 182 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liballos.tex+9−0

This diff is large: its 10 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libamoeba.tex+132−0

This diff is large: its 133 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libanydbm.tex+85−0

This diff is large: its 86 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libarray.tex+241−0

This diff is large: its 242 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libascii.tex+175−0

This diff is large: its 176 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libast.tex+57−0

This diff is large: its 58 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libasynchat.tex+254−0

This diff is large: its 255 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libasyncore.tex+260−0

This diff is large: its 261 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libatexit.tex+94−0

This diff is large: its 95 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libaudioop.tex+259−0

This diff is large: its 260 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbase64.tex+169−0

This diff is large: its 170 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbasehttp.tex+245−0

This diff is large: its 246 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbastion.tex+57−0

This diff is large: its 58 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbinascii.tex+147−0

This diff is large: its 148 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbinhex.tex+55−0

This diff is large: its 56 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbisect.tex+84−0

This diff is large: its 85 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbltin.tex+44−0

This diff is large: its 45 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbsddb.tex+208−0

This diff is large: its 209 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libbz2.tex+174−0

This diff is large: its 175 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcalendar.tex+304−0

This diff is large: its 305 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcd.tex+304−0

This diff is large: its 305 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcfgparser.tex+313−0

This diff is large: its 314 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcgi.tex+602−0

This diff is large: its 603 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcgihttp.tex+70−0

This diff is large: its 71 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcgitb.tex+67−0

This diff is large: its 68 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libchunk.tex+111−0

This diff is large: its 112 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcmath.tex+142−0

This diff is large: its 143 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcmd.tex+198−0

This diff is large: its 199 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcmp.tex+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcmpcache.tex+21−0

This diff is large: its 22 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcode.tex+173−0

This diff is large: its 174 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcodecs.tex+1348−0

This diff is large: its 1349 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcodeop.tex+103−0

This diff is large: its 104 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcollections.tex+341−0

This diff is large: its 342 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcolorsys.tex+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcommands.tex+62−0

This diff is large: its 63 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcompileall.tex+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libconsts.tex+31−0

This diff is large: its 32 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcontextlib.tex+130−0

This diff is large: its 131 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcookie.tex+260−0

This diff is large: its 261 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcookielib.tex+720−0

This diff is large: its 721 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcopy.tex+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcopyreg.tex+40−0

This diff is large: its 41 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcrypt.tex+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcrypto.tex+19−0

This diff is large: its 20 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcsv.tex+538−0

This diff is large: its 539 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libctypes.tex+2443−0

This diff is large: its 2444 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcurses.tex+1395−0

This diff is large: its 1396 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libcursespanel.tex+96−0

This diff is large: its 97 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdatetime.tex+1441−0

This diff is large: its 1442 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdbhash.tex+88−0

This diff is large: its 89 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdbm.tex+61−0

This diff is large: its 62 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdecimal.tex+1313−0

This diff is large: its 1314 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdifflib.tex+704−0

This diff is large: its 705 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdircache.tex+49−0

This diff is large: its 50 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdis.tex+706−0

This diff is large: its 707 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdl.tex+101−0

This diff is large: its 102 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdoctest.tex+1949−0

This diff is large: its 1950 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex+105−0

This diff is large: its 106 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdumbdbm.tex+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdummythread.tex+22−0

This diff is large: its 23 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libdummythreading.tex+22−0

This diff is large: its 23 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liberrno.tex+149−0

This diff is large: its 150 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libetree.tex+356−0

This diff is large: its 357 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libexcs.tex+466−0

This diff is large: its 467 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfcntl.tex+174−0

This diff is large: its 175 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfilecmp.tex+142−0

This diff is large: its 143 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfileinput.tex+192−0

This diff is large: its 193 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfl.tex+507−0

This diff is large: its 508 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfm.tex+94−0

This diff is large: its 95 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfnmatch.tex+86−0

This diff is large: its 87 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libformatter.tex+329−0

This diff is large: its 330 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfpectl.tex+127−0

This diff is large: its 128 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfpformat.tex+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libftplib.tex+288−0

This diff is large: its 289 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfuncs.tex+1321−0

This diff is large: its 1322 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfunctools.tex+132−0

This diff is large: its 133 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libfuture.tex+69−0

This diff is large: its 70 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgc.tex+196−0

This diff is large: its 197 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgdbm.tex+100−0

This diff is large: its 101 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgetopt.tex+154−0

This diff is large: its 155 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgetpass.tex+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgettext.tex+773−0

This diff is large: its 774 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgl.tex+224−0

This diff is large: its 225 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libglob.tex+51−0

This diff is large: its 52 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgopherlib.tex+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgrp.tex+49−0

This diff is large: its 50 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libgzip.tex+70−0

This diff is large: its 71 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libhashlib.tex+114−0

This diff is large: its 115 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libheapq.tex+214−0

This diff is large: its 215 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libhmac.tex+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libhotshot.tex+137−0

This diff is large: its 138 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libhtmllib.tex+181−0

This diff is large: its 182 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libhtmlparser.tex+169−0

This diff is large: its 170 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libhttplib.tex+434−0

This diff is large: its 435 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libimageop.tex+100−0

This diff is large: its 101 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libimaplib.tex+507−0

This diff is large: its 508 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libimgfile.tex+66−0

This diff is large: its 67 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libimghdr.tex+60−0

This diff is large: its 61 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libimp.tex+291−0

This diff is large: its 292 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libinspect.tex+393−0

This diff is large: its 394 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libintro.tex+53−0

This diff is large: its 54 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libitertools.tex+546−0

This diff is large: its 547 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libjpeg.tex+80−0

This diff is large: its 81 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libkeyword.tex+20−0

This diff is large: its 21 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liblinecache.tex+50−0

This diff is large: its 51 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liblocale.tex+527−0

This diff is large: its 528 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liblogging.tex+1729−0

This diff is large: its 1730 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmailbox.tex+1444−0

This diff is large: its 1445 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmailcap.tex+82−0

This diff is large: its 83 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmain.tex+16−0

This diff is large: its 17 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmarshal.tex+117−0

This diff is large: its 118 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmath.tex+209−0

This diff is large: its 210 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmd5.tex+92−0

This diff is large: its 93 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmhlib.tex+168−0

This diff is large: its 169 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmimetools.tex+120−0

This diff is large: its 121 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmimetypes.tex+226−0

This diff is large: its 227 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmimewriter.tex+80−0

This diff is large: its 81 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmimify.tex+94−0

This diff is large: its 95 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmisc.tex+7−0

This diff is large: its 8 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmm.tex+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmmap.tex+171−0

This diff is large: its 172 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmodulefinder.tex+51−0

This diff is large: its 52 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmsilib.tex+485−0

This diff is large: its 486 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmsvcrt.tex+109−0

This diff is large: its 110 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmultifile.tex+175−0

This diff is large: its 176 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libmutex.tex+57−0

This diff is large: its 58 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libnetrc.tex+68−0

This diff is large: its 69 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libnew.tex+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libni.tex+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libnis.tex+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libnntplib.tex+355−0

This diff is large: its 356 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libobjs.tex+24−0

This diff is large: its 25 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liboperator.tex+530−0

This diff is large: its 531 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liboptparse.tex+1888−0

This diff is large: its 1889 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libos.tex+2006−0

This diff is large: its 2007 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libossaudiodev.tex+401−0

This diff is large: its 402 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpanel.tex+74−0

This diff is large: its 75 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libparser.tex+711−0

This diff is large: its 712 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpdb.tex+456−0

This diff is large: its 457 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpickle.tex+888−0

This diff is large: its 889 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpickletools.tex+34−0

This diff is large: its 35 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpipes.tex+84−0

This diff is large: its 85 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpkgutil.tex+45−0

This diff is large: its 46 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libplatform.tex+221−0

This diff is large: its 222 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpopen2.tex+189−0

This diff is large: its 190 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpoplib.tex+181−0

This diff is large: its 182 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libposix.tex+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libposixfile.tex+175−0

This diff is large: its 176 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libposixpath.tex+281−0

This diff is large: its 282 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpprint.tex+210−0

This diff is large: its 211 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libprofile.tex+722−0

This diff is large: its 723 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpty.tex+44−0

This diff is large: its 45 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpwd.tex+57−0

This diff is large: its 58 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpyclbr.tex+102−0

This diff is large: its 103 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpycompile.tex+53−0

This diff is large: its 54 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpydoc.tex+67−0

This diff is large: its 68 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpyexpat.tex+777−0

This diff is large: its 778 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libpython.tex+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libqueue.tex+145−0

This diff is large: its 146 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libquopri.tex+61−0

This diff is large: its 62 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librandom.tex+309−0

This diff is large: its 310 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libre.tex+954−0

This diff is large: its 955 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libreadline.tex+196−0

This diff is large: its 197 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librepr.tex+133−0

This diff is large: its 134 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libresource.tex+215−0

This diff is large: its 216 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librestricted.tex+66−0

This diff is large: its 67 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librexec.tex+275−0

This diff is large: its 276 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librfc822.tex+336−0

This diff is large: its 337 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librgbimg.tex+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librlcompleter.tex+65−0

This diff is large: its 66 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librobotparser.tex+66−0

This diff is large: its 67 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/librunpy.tex+74−0

This diff is large: its 75 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsched.tex+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libselect.tex+132−0

This diff is large: its 133 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsets.tex+264−0

This diff is large: its 265 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsgi.tex+7−0

This diff is large: its 8 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsgmllib.tex+271−0

This diff is large: its 272 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsha.tex+83−0

This diff is large: its 84 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libshelve.tex+174−0

This diff is large: its 175 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libshlex.tex+274−0

This diff is large: its 275 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libshutil.tex+151−0

This diff is large: its 152 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsignal.tex+174−0

This diff is large: its 175 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsimplehttp.tex+86−0

This diff is large: its 87 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex+228−0

This diff is large: its 229 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsite.tex+88−0

This diff is large: its 89 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsmtpd.tex+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsmtplib.tex+295−0

This diff is large: its 296 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsndhdr.tex+41−0

This diff is large: its 42 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsocket.tex+910−0

This diff is large: its 911 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsocksvr.tex+293−0

This diff is large: its 294 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsomeos.tex+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libspwd.tex+48−0

This diff is large: its 49 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsqlite3.tex+642−0

This diff is large: its 643 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstat.tex+157−0

This diff is large: its 158 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstatvfs.tex+55−0

This diff is large: its 56 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstdtypes.tex+2095−0

This diff is large: its 2096 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstdwin.tex+832−0

This diff is large: its 833 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstring.tex+451−0

This diff is large: its 452 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstringio.tex+121−0

This diff is large: its 122 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstringprep.tex+136−0

This diff is large: its 137 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstrings.tex+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libstruct.tex+256−0

This diff is large: its 257 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsubprocess.tex+402−0

This diff is large: its 403 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsun.tex+5−0

This diff is large: its 6 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsunau.tex+218−0

This diff is large: its 219 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsunaudio.tex+146−0

This diff is large: its 147 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsymbol.tex+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsys.tex+617−0

This diff is large: its 618 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libsyslog.tex+76−0

This diff is large: its 77 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtabnanny.tex+62−0

This diff is large: its 63 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtarfile.tex+497−0

This diff is large: its 498 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtelnetlib.tex+215−0

This diff is large: its 216 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtempfile.tex+194−0

This diff is large: its 195 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtermios.tex+106−0

This diff is large: its 107 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtest.tex+278−0

This diff is large: its 279 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtextwrap.tex+181−0

This diff is large: its 182 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libthread.tex+173−0

This diff is large: its 174 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libthreading.tex+716−0

This diff is large: its 717 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtime.tex+461−0

This diff is large: its 462 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtimeit.tex+224−0

This diff is large: its 225 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtoken.tex+44−0

This diff is large: its 45 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtokenize.tex+119−0

This diff is large: its 120 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtrace.tex+125−0

This diff is large: its 126 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtraceback.tex+157−0

This diff is large: its 158 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtty.tex+34−0

This diff is large: its 35 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libturtle.tex+268−0

This diff is large: its 269 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libtypes.tex+215−0

This diff is large: its 216 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libundoc.tex+113−0

This diff is large: its 114 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libunicodedata.tex+160−0

This diff is large: its 161 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libunittest.tex+974−0

This diff is large: its 975 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libunix.tex+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liburllib.tex+497−0

This diff is large: its 498 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liburllib2.tex+872−0

This diff is large: its 873 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/liburlparse.tex+253−0

This diff is large: its 254 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libuser.tex+71−0

This diff is large: its 72 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libuserdict.tex+181−0

This diff is large: its 182 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libuu.tex+58−0

This diff is large: its 59 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libuuid.tex+233−0

This diff is large: its 234 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwarnings.tex+253−0

This diff is large: its 254 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwave.tex+169−0

This diff is large: its 170 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libweakref.tex+336−0

This diff is large: its 337 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwebbrowser.tex+173−0

This diff is large: its 174 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwhichdb.tex+20−0

This diff is large: its 21 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwinreg.tex+414−0

This diff is large: its 415 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwinsound.tex+142−0

This diff is large: its 143 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libwsgiref.tex+782−0

This diff is large: its 783 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libxdrlib.tex+251−0

This diff is large: its 252 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libxmllib.tex+287−0

This diff is large: its 288 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libxmlrpclib.tex+383−0

This diff is large: its 384 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libzipfile.tex+309−0

This diff is large: its 310 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libzipimport.tex+133−0

This diff is large: its 134 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/libzlib.tex+197−0

This diff is large: its 198 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/markup.tex+29−0

This diff is large: its 30 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/mimelib.tex+65−0

This diff is large: its 66 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/minidom-example.py+64−0

This diff is large: its 65 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/modules.tex+9−0

This diff is large: its 10 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/netdata.tex+6−0

This diff is large: its 7 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/numeric.tex+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/persistence.tex+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/required_1.py+20−0

This diff is large: its 21 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/required_2.py+41−0

This diff is large: its 42 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/adapter_datetime.py+14−0

This diff is large: its 15 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_1.py+16−0

This diff is large: its 17 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_2.py+17−0

This diff is large: its 18 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/collation_reverse.py+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/complete_statement.py+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py+3−0

This diff is large: its 4 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py+3−0

This diff is large: its 4 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/converter_point.py+47−0

This diff is large: its 48 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/createdb.py+28−0

This diff is large: its 29 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/execsql_fetchonerow.py+17−0

This diff is large: its 18 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/execsql_printall_1.py+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py+11−0

This diff is large: its 12 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py+12−0

This diff is large: its 13 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py+12−0

This diff is large: its 13 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/executemany_1.py+24−0

This diff is large: its 25 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/executemany_2.py+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/executescript.py+24−0

This diff is large: its 25 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/insert_more_people.py+16−0

This diff is large: its 17 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/md5func.py+11−0

This diff is large: its 12 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py+20−0

This diff is large: its 21 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/parse_colnames.py+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/pysqlite_datetime.py+20−0

This diff is large: its 21 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py+12−0

This diff is large: its 13 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py+6−0

This diff is large: its 7 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/shortcut_methods.py+21−0

This diff is large: its 22 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/simple_tableprinter.py+26−0

This diff is large: its 27 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py+42−0

This diff is large: its 43 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/tkinter.tex+1873−0

This diff is large: its 1874 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/tzinfo-examples.py+139−0

This diff is large: its 140 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/windows.tex+8−0

This diff is large: its 9 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmldom.tex+928−0

This diff is large: its 929 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmldomminidom.tex+285−0

This diff is large: its 286 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmldompulldom.tex+61−0

This diff is large: its 62 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmletree.tex+27−0

This diff is large: its 28 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmlsax.tex+143−0

This diff is large: its 144 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex+381−0

This diff is large: its 382 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmlsaxreader.tex+351−0

This diff is large: its 352 lines aren’t shown here.

sys/src/cmd/python/Doc/lib/xmlsaxutils.tex+81−0

This diff is large: its 82 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libaepack.tex+82−0

This diff is large: its 83 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libaetools.tex+83−0

This diff is large: its 84 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libaetypes.tex+135−0

This diff is large: its 136 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libautogil.tex+26−0

This diff is large: its 27 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libcolorpicker.tex+23−0

This diff is large: its 24 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libframework.tex+314−0

This diff is large: its 315 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libgensuitemodule.tex+64−0

This diff is large: its 65 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libmac.tex+29−0

This diff is large: its 30 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libmacfs.tex+241−0

This diff is large: its 242 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libmacic.tex+123−0

This diff is large: its 124 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libmacos.tex+90−0

This diff is large: its 91 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libmacostools.tex+105−0

This diff is large: its 106 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libmacui.tex+266−0

This diff is large: its 267 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libminiae.tex+65−0

This diff is large: its 66 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/libscrap.tex+42−0

This diff is large: its 43 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/mac.tex+89−0

This diff is large: its 90 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/scripting.tex+101−0

This diff is large: its 102 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/toolbox.tex+173−0

This diff is large: its 174 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/undoc.tex+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Doc/mac/using.tex+218−0

This diff is large: its 219 lines aren’t shown here.

sys/src/cmd/python/Doc/paper-a4/pypaper.sty+17−0

This diff is large: its 18 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/SynopsisTable.pm+95−0

This diff is large: its 96 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/distutils.perl+21−0

This diff is large: its 22 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/howto.perl+12−0

This diff is large: its 13 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/isilo.perl+12−0

This diff is large: its 13 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/l2hinit.perl+801−0

This diff is large: its 802 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/ltxmarkup.perl+67−0

This diff is large: its 68 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/manual.perl+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Doc/perl/python.perl+2172−0

This diff is large: its 2173 lines aren’t shown here.

sys/src/cmd/python/Doc/python-docs.txt+183−0

This diff is large: its 184 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref.tex+68−0

This diff is large: its 69 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref1.tex+136−0

This diff is large: its 137 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref2.tex+731−0

This diff is large: its 732 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref3.tex+2225−0

This diff is large: its 2226 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref4.tex+219−0

This diff is large: its 220 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref5.tex+1325−0

This diff is large: its 1326 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref6.tex+928−0

This diff is large: its 929 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref7.tex+544−0

This diff is large: its 545 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/ref8.tex+112−0

This diff is large: its 113 lines aren’t shown here.

sys/src/cmd/python/Doc/ref/reswords.py+23−0

This diff is large: its 24 lines aren’t shown here.

sys/src/cmd/python/Doc/templates/howto.tex+112−0

This diff is large: its 113 lines aren’t shown here.

sys/src/cmd/python/Doc/templates/manual.tex+89−0

This diff is large: its 90 lines aren’t shown here.

sys/src/cmd/python/Doc/templates/module.tex+170−0

This diff is large: its 171 lines aren’t shown here.

sys/src/cmd/python/Doc/templates/whatsnewXY.tex+149−0

This diff is large: its 150 lines aren’t shown here.

sys/src/cmd/python/Doc/tests/math.tex+16−0

This diff is large: its 17 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/distutils.sty+33−0

This diff is large: its 34 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/fancyhdr.sty+329−0

This diff is large: its 330 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/fncychap.sty+433−0

This diff is large: its 434 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/howto.cls+109−0

This diff is large: its 110 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty+40−0

This diff is large: its 41 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/manual.cls+155−0

This diff is large: its 156 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/pypaper.sty+18−0

This diff is large: its 19 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/python.ist+11−0

This diff is large: its 12 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/python.sty+1327−0

This diff is large: its 1328 lines aren’t shown here.

sys/src/cmd/python/Doc/texinputs/underscore.sty+232−0

This diff is large: its 233 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/anno-api.py+71−0

This diff is large: its 72 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/buildindex.py+388−0

This diff is large: its 389 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/checkargs.pm+112−0

This diff is large: its 113 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/cklatex+26−0

This diff is large: its 27 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/cmpcsyms+157−0

This diff is large: its 158 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/custlib.py+78−0

This diff is large: its 79 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/findcsyms+136−0

This diff is large: its 137 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/findmodrefs+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/findsyms+128−0

This diff is large: its 129 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/fix_hack+2−0

This diff is large: its 3 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/fix_libaux.sed+3−0

This diff is large: its 4 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/fixinfo.el+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/getpagecounts+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/getversioninfo+71−0

This diff is large: its 72 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/html2texi.pl+1750−0

This diff is large: its 1751 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/indfix.py+100−0

This diff is large: its 101 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/keywords.py+19−0

This diff is large: its 20 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/listmodules+183−0

This diff is large: its 184 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/listmodules.py+126−0

This diff is large: its 127 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/makesec.sh+129−0

This diff is large: its 130 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/mkackshtml+66−0

This diff is large: its 67 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/mkhowto+659−0

This diff is large: its 660 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/mkinfo+65−0

This diff is large: its 66 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/mkmodindex+158−0

This diff is large: its 159 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/mkpkglist+85−0

This diff is large: its 86 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/mksourcepkg+164−0

This diff is large: its 165 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/node2label.pl+71−0

This diff is large: its 72 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/prechm.py+519−0

This diff is large: its 520 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/push-docs.sh+138−0

This diff is large: its 139 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/py2texi.el+970−0

This diff is large: its 971 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/refcounts.py+98−0

This diff is large: its 99 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/rewrite.py+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/Makefile+67−0

This diff is large: its 68 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/README+58−0

This diff is large: its 59 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/conversion.xml+914−0

This diff is large: its 915 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py+1073−0

This diff is large: its 1074 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py+264−0

This diff is large: its 265 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py+312−0

This diff is large: its 313 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/latex2esis.py+565−0

This diff is large: its 566 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/sgmlconv/make.rules+48−0

This diff is large: its 49 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/support.py+202−0

This diff is large: its 203 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/toc2bkm.py+160−0

This diff is large: its 161 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/undoc_symbols.py+94−0

This diff is large: its 95 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/update-docs.sh+31−0

This diff is large: its 32 lines aren’t shown here.

sys/src/cmd/python/Doc/tools/whichlibs+2−0

This diff is large: its 3 lines aren’t shown here.

sys/src/cmd/python/Doc/tut/glossary.tex+352−0

This diff is large: its 353 lines aren’t shown here.

sys/src/cmd/python/Doc/tut/tut.tex+5907−0

This diff is large: its 5908 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/Makefile+3−0

This diff is large: its 4 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex+1337−0

This diff is large: its 1338 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex+868−0

This diff is large: its 869 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex+1466−0

This diff is large: its 1467 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex+2380−0

This diff is large: its 2381 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex+1757−0

This diff is large: its 1758 lines aren’t shown here.

sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex+2530−0

This diff is large: its 2531 lines aren’t shown here.

sys/src/cmd/python/Extra/dummy.c+6−0

This diff is large: its 7 lines aren’t shown here.

sys/src/cmd/python/Extra/mercurial/base85.c+155−0

This diff is large: its 156 lines aren’t shown here.

sys/src/cmd/python/Extra/mercurial/bdiff.c+401−0

This diff is large: its 402 lines aren’t shown here.

sys/src/cmd/python/Extra/mercurial/diffhelpers.c+156−0

This diff is large: its 157 lines aren’t shown here.

sys/src/cmd/python/Extra/mercurial/mpatch.c+444−0

This diff is large: its 445 lines aren’t shown here.

sys/src/cmd/python/Extra/mercurial/osutil.c+534−0

This diff is large: its 535 lines aren’t shown here.

sys/src/cmd/python/Extra/mercurial/parsers.c+435−0

This diff is large: its 436 lines aren’t shown here.

sys/src/cmd/python/Extra/mkfile+16−0

This diff is large: its 17 lines aren’t shown here.

sys/src/cmd/python/Grammar/Grammar+148−0

This diff is large: its 149 lines aren’t shown here.

sys/src/cmd/python/Include/Python-ast.h+501−0

This diff is large: its 502 lines aren’t shown here.

sys/src/cmd/python/Include/Python.h+173−0

This diff is large: its 174 lines aren’t shown here.

sys/src/cmd/python/Include/abstract.h+1276−0

This diff is large: its 1277 lines aren’t shown here.

sys/src/cmd/python/Include/asdl.h+45−0

This diff is large: its 46 lines aren’t shown here.

sys/src/cmd/python/Include/ast.h+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Include/bitset.h+32−0

This diff is large: its 33 lines aren’t shown here.

sys/src/cmd/python/Include/boolobject.h+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Include/bufferobject.h+33−0

This diff is large: its 34 lines aren’t shown here.

sys/src/cmd/python/Include/cStringIO.h+70−0

This diff is large: its 71 lines aren’t shown here.

sys/src/cmd/python/Include/cellobject.h+28−0

This diff is large: its 29 lines aren’t shown here.

sys/src/cmd/python/Include/ceval.h+157−0

This diff is large: its 158 lines aren’t shown here.

sys/src/cmd/python/Include/classobject.h+81−0

This diff is large: its 82 lines aren’t shown here.

sys/src/cmd/python/Include/cobject.h+54−0

This diff is large: its 55 lines aren’t shown here.

sys/src/cmd/python/Include/code.h+94−0

This diff is large: its 95 lines aren’t shown here.

sys/src/cmd/python/Include/codecs.h+167−0

This diff is large: its 168 lines aren’t shown here.

sys/src/cmd/python/Include/compile.h+39−0

This diff is large: its 40 lines aren’t shown here.

sys/src/cmd/python/Include/complexobject.h+58−0

This diff is large: its 59 lines aren’t shown here.

sys/src/cmd/python/Include/datetime.h+245−0

This diff is large: its 246 lines aren’t shown here.

sys/src/cmd/python/Include/descrobject.h+91−0

This diff is large: its 92 lines aren’t shown here.

sys/src/cmd/python/Include/dictobject.h+141−0

This diff is large: its 142 lines aren’t shown here.

sys/src/cmd/python/Include/enumobject.h+17−0

This diff is large: its 18 lines aren’t shown here.

sys/src/cmd/python/Include/errcode.h+36−0

This diff is large: its 37 lines aren’t shown here.

sys/src/cmd/python/Include/eval.h+25−0

This diff is large: its 26 lines aren’t shown here.

sys/src/cmd/python/Include/fileobject.h+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Include/floatobject.h+100−0

This diff is large: its 101 lines aren’t shown here.

sys/src/cmd/python/Include/frameobject.h+81−0

This diff is large: its 82 lines aren’t shown here.

sys/src/cmd/python/Include/funcobject.h+76−0

This diff is large: its 77 lines aren’t shown here.

sys/src/cmd/python/Include/genobject.h+37−0

This diff is large: its 38 lines aren’t shown here.

sys/src/cmd/python/Include/graminit.h+84−0

This diff is large: its 85 lines aren’t shown here.

sys/src/cmd/python/Include/grammar.h+93−0

This diff is large: its 94 lines aren’t shown here.

sys/src/cmd/python/Include/import.h+64−0

This diff is large: its 65 lines aren’t shown here.

sys/src/cmd/python/Include/intobject.h+64−0

This diff is large: its 65 lines aren’t shown here.

sys/src/cmd/python/Include/intrcheck.h+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Include/iterobject.h+23−0

This diff is large: its 24 lines aren’t shown here.

sys/src/cmd/python/Include/listobject.h+67−0

This diff is large: its 68 lines aren’t shown here.

sys/src/cmd/python/Include/longintrepr.h+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Include/longobject.h+114−0

This diff is large: its 115 lines aren’t shown here.

sys/src/cmd/python/Include/marshal.h+25−0

This diff is large: its 26 lines aren’t shown here.

sys/src/cmd/python/Include/metagrammar.h+18−0

This diff is large: its 19 lines aren’t shown here.

sys/src/cmd/python/Include/methodobject.h+91−0

This diff is large: its 92 lines aren’t shown here.

sys/src/cmd/python/Include/modsupport.h+133−0

This diff is large: its 134 lines aren’t shown here.

sys/src/cmd/python/Include/moduleobject.h+24−0

This diff is large: its 25 lines aren’t shown here.

sys/src/cmd/python/Include/node.h+40−0

This diff is large: its 41 lines aren’t shown here.

sys/src/cmd/python/Include/object.h+868−0

This diff is large: its 869 lines aren’t shown here.

sys/src/cmd/python/Include/objimpl.h+336−0

This diff is large: its 337 lines aren’t shown here.

sys/src/cmd/python/Include/opcode.h+152−0

This diff is large: its 153 lines aren’t shown here.

sys/src/cmd/python/Include/osdefs.h+55−0

This diff is large: its 56 lines aren’t shown here.

sys/src/cmd/python/Include/parsetok.h+50−0

This diff is large: its 51 lines aren’t shown here.

sys/src/cmd/python/Include/patchlevel.h+40−0

This diff is large: its 41 lines aren’t shown here.

sys/src/cmd/python/Include/pgen.h+18−0

This diff is large: its 19 lines aren’t shown here.

sys/src/cmd/python/Include/pgenheaders.h+42−0

This diff is large: its 43 lines aren’t shown here.

sys/src/cmd/python/Include/py_curses.h+176−0

This diff is large: its 177 lines aren’t shown here.

sys/src/cmd/python/Include/pyarena.h+62−0

This diff is large: its 63 lines aren’t shown here.

sys/src/cmd/python/Include/pydebug.h+34−0

This diff is large: its 35 lines aren’t shown here.

sys/src/cmd/python/Include/pyerrors.h+334−0

This diff is large: its 335 lines aren’t shown here.

sys/src/cmd/python/Include/pyexpat.h+47−0

This diff is large: its 48 lines aren’t shown here.

sys/src/cmd/python/Include/pyfpe.h+176−0

This diff is large: its 177 lines aren’t shown here.

sys/src/cmd/python/Include/pygetopt.h+17−0

This diff is large: its 18 lines aren’t shown here.

sys/src/cmd/python/Include/pymactoolbox.h+189−0

This diff is large: its 190 lines aren’t shown here.

sys/src/cmd/python/Include/pymem.h+105−0

This diff is large: its 106 lines aren’t shown here.

sys/src/cmd/python/Include/pyport.h+771−0

This diff is large: its 772 lines aren’t shown here.

sys/src/cmd/python/Include/pystate.h+195−0

This diff is large: its 196 lines aren’t shown here.

sys/src/cmd/python/Include/pystrtod.h+18−0

This diff is large: its 19 lines aren’t shown here.

sys/src/cmd/python/Include/pythonrun.h+171−0

This diff is large: its 172 lines aren’t shown here.

sys/src/cmd/python/Include/pythread.h+47−0

This diff is large: its 48 lines aren’t shown here.

sys/src/cmd/python/Include/rangeobject.h+28−0

This diff is large: its 29 lines aren’t shown here.

sys/src/cmd/python/Include/setobject.h+93−0

This diff is large: its 94 lines aren’t shown here.

sys/src/cmd/python/Include/sliceobject.h+43−0

This diff is large: its 44 lines aren’t shown here.

sys/src/cmd/python/Include/stringobject.h+183−0

This diff is large: its 184 lines aren’t shown here.

sys/src/cmd/python/Include/structmember.h+93−0

This diff is large: its 94 lines aren’t shown here.

sys/src/cmd/python/Include/structseq.h+41−0

This diff is large: its 42 lines aren’t shown here.

sys/src/cmd/python/Include/symtable.h+103−0

This diff is large: its 104 lines aren’t shown here.

sys/src/cmd/python/Include/sysmodule.h+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Include/timefuncs.h+23−0

This diff is large: its 24 lines aren’t shown here.

sys/src/cmd/python/Include/token.h+83−0

This diff is large: its 84 lines aren’t shown here.

sys/src/cmd/python/Include/traceback.h+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Include/tupleobject.h+57−0

This diff is large: its 58 lines aren’t shown here.

sys/src/cmd/python/Include/ucnhash.h+31−0

This diff is large: its 32 lines aren’t shown here.

sys/src/cmd/python/Include/unicodeobject.h+1265−0

This diff is large: its 1266 lines aren’t shown here.

sys/src/cmd/python/Include/weakrefobject.h+75−0

This diff is large: its 76 lines aren’t shown here.

sys/src/cmd/python/LICENSE+270−0

This diff is large: its 271 lines aren’t shown here.

sys/src/cmd/python/Misc/ACKS+698−0

This diff is large: its 699 lines aren’t shown here.

sys/src/cmd/python/Misc/AIX-NOTES+155−0

This diff is large: its 156 lines aren’t shown here.

sys/src/cmd/python/Misc/BeOS-NOTES+43−0

This diff is large: its 44 lines aren’t shown here.

sys/src/cmd/python/Misc/BeOS-setup.py+574−0

This diff is large: its 575 lines aren’t shown here.

sys/src/cmd/python/Misc/NEWS+2782−0

This diff is large: its 2783 lines aren’t shown here.

sys/src/cmd/python/Misc/NEWS.help+73−0

This diff is large: its 74 lines aren’t shown here.

sys/src/cmd/python/Misc/PURIFY.README+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Misc/Porting+42−0

This diff is large: its 43 lines aren’t shown here.

sys/src/cmd/python/Misc/README+33−0

This diff is large: its 34 lines aren’t shown here.

sys/src/cmd/python/Misc/README.OpenBSD+38−0

This diff is large: its 39 lines aren’t shown here.

sys/src/cmd/python/Misc/README.coverity+22−0

This diff is large: its 23 lines aren’t shown here.

sys/src/cmd/python/Misc/README.klocwork+30−0

This diff is large: its 31 lines aren’t shown here.

sys/src/cmd/python/Misc/README.valgrind+97−0

This diff is large: its 98 lines aren’t shown here.

sys/src/cmd/python/Misc/RFD+114−0

This diff is large: its 115 lines aren’t shown here.

sys/src/cmd/python/Misc/RPM/README+16−0

This diff is large: its 17 lines aren’t shown here.

sys/src/cmd/python/Misc/RPM/python-2.5.spec+395−0

This diff is large: its 396 lines aren’t shown here.

sys/src/cmd/python/Misc/SpecialBuilds.txt+261−0

This diff is large: its 262 lines aren’t shown here.

sys/src/cmd/python/Misc/Vim/python.vim+147−0

This diff is large: its 148 lines aren’t shown here.

sys/src/cmd/python/Misc/Vim/syntax_test.py+63−0

This diff is large: its 64 lines aren’t shown here.

sys/src/cmd/python/Misc/Vim/vim_syntax.py+226−0

This diff is large: its 227 lines aren’t shown here.

sys/src/cmd/python/Misc/Vim/vimrc+95−0

This diff is large: its 96 lines aren’t shown here.

sys/src/cmd/python/Misc/build.sh+227−0

This diff is large: its 228 lines aren’t shown here.

sys/src/cmd/python/Misc/cheatsheet+2279−0

This diff is large: its 2280 lines aren’t shown here.

sys/src/cmd/python/Misc/developers.txt+141−0

This diff is large: its 142 lines aren’t shown here.

sys/src/cmd/python/Misc/find_recursionlimit.py+87−0

This diff is large: its 88 lines aren’t shown here.

sys/src/cmd/python/Misc/gdbinit+140−0

This diff is large: its 141 lines aren’t shown here.

sys/src/cmd/python/Misc/indent.pro+15−0

This diff is large: its 16 lines aren’t shown here.

sys/src/cmd/python/Misc/pymemcompat.h+85−0

This diff is large: its 86 lines aren’t shown here.

sys/src/cmd/python/Misc/python-config.in+53−0

This diff is large: its 54 lines aren’t shown here.

sys/src/cmd/python/Misc/python-mode.el+3768−0

This diff is large: its 3769 lines aren’t shown here.

sys/src/cmd/python/Misc/python.man+397−0

This diff is large: its 398 lines aren’t shown here.

sys/src/cmd/python/Misc/setuid-prog.c+176−0

This diff is large: its 177 lines aren’t shown here.

sys/src/cmd/python/Misc/valgrind-python.supp+349−0

This diff is large: its 350 lines aren’t shown here.

sys/src/cmd/python/Misc/vgrindefs+10−0

This diff is large: its 11 lines aren’t shown here.

sys/src/cmd/python/Modules/Setup+488−0

This diff is large: its 489 lines aren’t shown here.

sys/src/cmd/python/Modules/Setup.config+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Modules/Setup.config.in+13−0

This diff is large: its 14 lines aren’t shown here.

sys/src/cmd/python/Modules/Setup.dist+487−0

This diff is large: its 488 lines aren’t shown here.

sys/src/cmd/python/Modules/Setup.local+1−0

This diff is large: its 2 lines aren’t shown here.

sys/src/cmd/python/Modules/_bisectmodule.c+235−0

This diff is large: its 236 lines aren’t shown here.

sys/src/cmd/python/Modules/_bsddb.c+6047−0

This diff is large: its 6048 lines aren’t shown here.

sys/src/cmd/python/Modules/_codecsmodule.c+934−0

This diff is large: its 935 lines aren’t shown here.

sys/src/cmd/python/Modules/_csv.c+1604−0

This diff is large: its 1605 lines aren’t shown here.

This diff is larger than a page shows: the files after these aren’t listed. Clone the repository to see all of it.